I'm trying to load a file with pack://application: The file is situated in the root of my project but I keep getting a null reference error. However When I do an absolute reference it finds the file and loads just fine.
What am I missing here?
This doesn't work
var txt = Application.GetContentStream(new Uri(#"pack://application:,,,/Layout.xml"));
string full = new StreamReader(txt.Stream).ReadToEnd();
or any variation with Pack://Application,,,/
This works, but I don't want to use it and seems bad practice anyway
var path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, (AppDomain.CurrentDomain.BaseDirectory.Length - 10));
var txt = path + #"Layout.xml";
string full = new StreamReader(txt).ReadToEnd();
First, ensure that the file is definitely copied into your output ./bin/ directory on compile:
This worked perfectly for me in my WPF application:
const string imagePath = #"pack://application:,,,/Test.txt";
StreamResourceInfo imageInfo = Application.GetResourceStream(new Uri(imagePath));
byte[] imageBytes = ReadFully(imageInfo.Stream);
If you want to read it as binary (e.g. read an image file), you'll need this helper function. You probably won't need this, as you're reading an .xml file.
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
For more, see Microsoft on Pack URIs in WPF.
I'm not familiar with the way you are trying to achieve this. I use to solve this kind of problem differently:
First, embed the file you are trying to access in you application. This is done by setting the Build-Step-Property of the File (Properties-Window, when file is selected in VS) to Embedded Resource.
In your application, you can recieve a stream to that resource like that:
var stream = this.GetType().Assembly.GetManifestResourceStream("Namespace.yourfile.txt");
If you are unsure of the string you have to pass to GetManifestResourceStream(..), you can inspect what embedded resources are available and look for the one that is accociated with your file like so:
var embeddedResources = this.GetType().Assembly.GetManifestResourceNames()
Related
I have a .docx file located on my virtual machine desktop which I want to write down to a stream.
So far this is what I have tried
byte[] buffer = new byte[32768];
string path = #"\\officeblrhome.somedomain\UserData$\username\Desktop\filename.docx";
var memoryStr = new MemoryStream();
memoryStr.Write(System.IO.File.ReadAllBytytes(path), 0 , buffer.Length);
using (WordprocessingDocumenet doc = WordprocessingDocument.Open(memoryStr, true)
And I get the an error that the file contains corrupted data. Is it possible that my path is wrong? If it is how to get the valid path from the VM? The word file itself is not corrupted.
I made few changes to the code and seems that it's working
byte[] buffer = System.IO.File.ReadAllBytytes(path);
stream.Flush();
stream.Position = 0;
Hi there iam trying to convert text to speech (wav) in the memorystream convert it to mp3 and then play it on the users page.so need i help what to do next?
here is my asmx code :
[WebMethod]
public byte[] StartSpeak(string Word)
{
MemoryStream ms = new MemoryStream();
using (System.Speech.Synthesis.SpeechSynthesizer synhesizer = new System.Speech.Synthesis.SpeechSynthesizer())
{
synhesizer.SelectVoiceByHints(System.Speech.Synthesis.VoiceGender.NotSet, System.Speech.Synthesis.VoiceAge.NotSet, 0, new System.Globalization.CultureInfo("en-US"));
synhesizer.SetOutputToWaveStream(ms);
synhesizer.Speak(Word);
}
return ms.ToArray();
}
Thanks.
Just wanted to post my example too using NAudio.Lame:
NuGet:
Install-Package NAudio.Lame
Code Snip: Mine obviously returns a byte[] - I have a separate save to disk method b/c I think it makes unit testing easier.
public static byte[] ConvertWavToMp3(byte[] wavFile)
{
using(var retMs = new MemoryStream())
using (var ms = new MemoryStream(wavFile))
using(var rdr = new WaveFileReader(ms))
using (var wtr = new LameMP3FileWriter(retMs, rdr.WaveFormat, 128))
{
rdr.CopyTo(wtr);
return retMs.ToArray();
}
}
You need an MP3 compressor library. I use Lame via the Yeti Lame wrapper. You can find code and a sample project here.
Steps to get this working:
Copy the following files from MP3Compressor to your project:
AudioWriters.cs
Lame.cs
Lame_enc.dll
Mp3Writer.cs
Mp3WriterConfig.cs
WaveNative.cs
WriterConfig.cs
In the project properties for Lame_enc.dll set the Copy to Output property to Copy if newer or Copy always.
Edit Lame.cs and replace all instances of:
[DllImport("Lame_enc.dll")]
with:
[DllImport("Lame_enc.dll", CallingConvention = CallingConvention.Cdecl)]
Add the following code to your project:
public static Byte[] WavToMP3(byte[] wavFile)
{
using (MemoryStream source = new MemoryStream(wavFile))
using (NAudio.Wave.WaveFileReader rdr = new NAudio.Wave.WaveFileReader(source))
{
WaveLib.WaveFormat fmt = new WaveLib.WaveFormat(rdr.WaveFormat.SampleRate, rdr.WaveFormat.BitsPerSample, rdr.WaveFormat.Channels);
// convert to MP3 at 96kbit/sec...
Yeti.Lame.BE_CONFIG conf = new Yeti.Lame.BE_CONFIG(fmt, 96);
// Allocate a 1-second buffer
int blen = rdr.WaveFormat.AverageBytesPerSecond;
byte[] buffer = new byte[blen];
// Do conversion
using (MemoryStream output = new MemoryStream())
{
Yeti.MMedia.Mp3.Mp3Writer mp3 = new Yeti.MMedia.Mp3.Mp3Writer(output, fmt, conf);
int readCount;
while ((readCount = rdr.Read(buffer, 0, blen)) > 0)
mp3.Write(buffer, 0, readCount);
mp3.Close();
return output.ToArray();
}
}
}
Either add a reference to System.Windows.Forms to your project (if it's not there already), or edit AudioWriter.cs and WriterConfig.cs to remove the references. Both of these have a using System.Windows.Forms; that you can remove, and WriterConfig.cs has a ConfigControl declaration that needs to be removed/commented out.
Once all of that is done you should have a functional in-memory wave-file to MP3 converter that you can use to convert the WAV file that you are getting from the SpeechSynthesizer into an MP3.
This is a bit old now, but since you haven't accepted the answer I previously provided...
I have recently built an extension for NAudio that encapsulates the LAME library to provide simplified MP3 encoding.
Use the NuGet package manager to find NAudio.Lame. Basic example for using it available here.
Assuming you're trying to convert the output into MP3, you need something that can handle transcoding the audio. There are a number of tools available, but my personal preference is FFmpeg. It's a command line tool so you will need to take that into account, but otherwise it's very easy to use.
There's lots of information online, but you can start by checking out their documentation here.
I had a similar requirement in .net4.0 to convert 8bit 8Khz mono wav and used the following code
public void WavToMp3(string wavPath, string fileId)
{
var tempMp3Path = TempPath + "tempFiles\\" + fileId + ".mp3";
var mp3strm = new FileStream(tempMp3Path, FileMode.Create);
try
{
using (var reader = new WaveFileReader(wavPath))
{
var blen = 65536;
var buffer = new byte[blen];
int rc;
var bit16WaveFormat = new WaveFormat(16000, 16, 1);
using (var conversionStream = new WaveFormatConversionStream(bit16WaveFormat, reader))
{
var targetMp3Format = new WaveLib.WaveFormat(16000, 16, 1);
using (var mp3Wri = new Mp3Writer(mp3strm, new Mp3WriterConfig(targetMp3Format, new BE_CONFIG(targetMp3Format,64))))
{
while ((rc = conversionStream.Read(buffer, 0, blen)) > 0) mp3Wri.Write(buffer, 0, rc);
mp3strm.Flush();
conversionStream.Close();
}
}
reader.Close();
}
File.Move(tempMp3Path, TempPath + fileId + ".mp3");
}
finally
{
mp3strm.Close();
}
}
Prerequists:
.net 4 compiled yeti library (to obtain it download this older one (http://www.codeproject.com/KB/audio-video/MP3Compressor/MP3Compressor.zip) and convert it to .net4.0 then build the solution to obtain the new version dlls)
download the NAudio libraries (as Lame support 16bit wav sample only i had to first convert it from 8bit to 16bit wav)
I have used a buffer size of 64kpbs (my custom requirement)
have a try:
using (WaveStream waveStream = WaveFormatConversionStream.CreatePcmStream(new
Mp3FileReader(inputStream)))
using (WaveFileWriter waveFileWriter = new WaveFileWriter(outputStream, waveStream.WaveFormat))
{
byte[] bytes = new byte[waveStream.Length];
waveStream.Position = 0;
waveStream.Read(bytes, 0, waveStream.Length);
waveFileWriter.WriteData(bytes, 0, bytes.Length);
waveFileWriter.Flush();
}
I'm searching a way to add embedded resource to my solution. This resources will be folders with a lot of files in them. On user demand they need to be decompressed.
I'm searching for a way do store such folders in executable without involving third-party libraries (Looks rather stupid, but this is the task).
I have found, that I can GZip and UnGZip them using standard libraries. But GZip handles single file only. In such cases TAR should come to the scene. But I haven't found TAR implementation among standard classes.
Maybe it possible decompress TAR with bare C#?
While looking for a quick answer to the same question, I came across this thread, and was not entirely satisfied with the current answers, as they all point to using third-party dependencies to much larger libraries, all just to achieve simple extraction of a tar.gz file to disk.
While the gz format could be considered rather complicated, tar on the other hand is quite simple. At its core, it just takes a bunch of files, prepends a 500 byte header (but takes 512 bytes) to each describing the file, and writes them all to single archive on a 512 byte alignment. There is no compression, that is typically handled by compressing the created file to a gz archive, which .NET conveniently has built-in, which takes care of all the hard part.
Having looked at the spec for the tar format, there are only really 2 values (especially on Windows) we need to pick out from the header in order to extract the file from a stream. The first is the name, and the second is size. Using those two values, we need only seek to the appropriate position in the stream and copy the bytes to a file.
I made a very rudimentary, down-and-dirty method to extract a tar archive to a directory, and added some helper functions for opening from a stream or filename, and decompressing the gz file first using built-in functions.
The primary method is this:
public static void ExtractTar(Stream stream, string outputDir)
{
var buffer = new byte[100];
while (true)
{
stream.Read(buffer, 0, 100);
var name = Encoding.ASCII.GetString(buffer).Trim('\0');
if (String.IsNullOrWhiteSpace(name))
break;
stream.Seek(24, SeekOrigin.Current);
stream.Read(buffer, 0, 12);
var size = Convert.ToInt64(Encoding.ASCII.GetString(buffer, 0, 12).Trim(), 8);
stream.Seek(376L, SeekOrigin.Current);
var output = Path.Combine(outputDir, name);
if (!Directory.Exists(Path.GetDirectoryName(output)))
Directory.CreateDirectory(Path.GetDirectoryName(output));
using (var str = File.Open(output, FileMode.OpenOrCreate, FileAccess.Write))
{
var buf = new byte[size];
stream.Read(buf, 0, buf.Length);
str.Write(buf, 0, buf.Length);
}
var pos = stream.Position;
var offset = 512 - (pos % 512);
if (offset == 512)
offset = 0;
stream.Seek(offset, SeekOrigin.Current);
}
}
And here is a few helper functions for opening from a file, and automating first decompressing a tar.gz file/stream before extracting.
public static void ExtractTarGz(string filename, string outputDir)
{
using (var stream = File.OpenRead(filename))
ExtractTarGz(stream, outputDir);
}
public static void ExtractTarGz(Stream stream, string outputDir)
{
// A GZipStream is not seekable, so copy it first to a MemoryStream
using (var gzip = new GZipStream(stream, CompressionMode.Decompress))
{
const int chunk = 4096;
using (var memStr = new MemoryStream())
{
int read;
var buffer = new byte[chunk];
do
{
read = gzip.Read(buffer, 0, chunk);
memStr.Write(buffer, 0, read);
} while (read == chunk);
memStr.Seek(0, SeekOrigin.Begin);
ExtractTar(memStr, outputDir);
}
}
}
public static void ExtractTar(string filename, string outputDir)
{
using (var stream = File.OpenRead(filename))
ExtractTar(stream, outputDir);
}
Here is a gist of the full file with some comments.
Tar-cs will do the job, but it is quite slow. I would recommend using SharpCompress which is significantly quicker. It also supports other compression types and it has been updated recently.
using System;
using System.IO;
using SharpCompress.Common;
using SharpCompress.Reader;
private static String directoryPath = #"C:\Temp";
public static void unTAR(String tarFilePath)
{
using (Stream stream = File.OpenRead(tarFilePath))
{
var reader = ReaderFactory.Open(stream);
while (reader.MoveToNextEntry())
{
if (!reader.Entry.IsDirectory)
{
ExtractionOptions opt = new ExtractionOptions {
ExtractFullPath = true,
Overwrite = true
};
reader.WriteEntryToDirectory(directoryPath, opt);
}
}
}
}
See tar-cs
using (FileStream unarchFile = File.OpenRead(tarfile))
{
TarReader reader = new TarReader(unarchFile);
reader.ReadToEnd("out_dir");
}
Since you are not allowed to use outside libraries, you are not restricted to a specific format of the tar file either. In fact, they don't even need it to be all in the same file.
You can write your own tar-like utility in C# that walks a directory tree, and produces two files: a "header" file that consists of a serialized dictionary mapping System.IO.Path instances to an offset/length pairs, and a big file containing the content of individual files concatenated into one giant blob. This is not a trivial task, but it's not overly complicated either.
there are 2 ways to compress/decompress in .NET first you can use Gzipstream class and DeflatStream both can actually do compress your files in .gz format so if you compressed any file in Gzipstream it can be opened with any popular compression applications such as winzip/ winrar, 7zip but you can't open compressed file with DeflatStream. these two classes are from .NET 2.
and there is another way which is Package class it's actually same as Gzipstream and DeflatStream the only different is you can compress multiple files which then can be opened with winzip/ winrar, 7zip.so that's all .NET has. but it's not even generic .zip file,
it something Microsoft uses to compress their *x extension office files. if you decompress any docx file with package class you can see everything stored in it. so don't use .NET libraries for compressing or even decompressing cause you can't even make a generic compress file or even decompress a generic zip file. you have to consider for a third party library such as
http://www.icsharpcode.net/OpenSource/SharpZipLib/
or implement everything from the ground floor.
I have to pass the path of a config file to a framework method (Gurok SmartInspect). The config file is an embedded resource of the assembly. Currently I read the file from the assembly and store it outside and then pass the pathName. Is there a better / less complicated way to achieve this goal, without copying the file?
private static void ConfigLogger()
{
const string embeddedFileName = "xxx.SmartInspect.properties";
const string configFileName = "SmartInspect.properties";
ExtractFileFromAssembly(embeddedFileName, configFileName);
SiAuto.Si.LoadConfiguration(configFileName);
}
private static void ExtractFileFromAssembly(string assemblyFileName, string configFileName)
{
using (Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(assemblyFileName) )
{
byte[] buffer = new byte[s.Length];
int read = s.Read(buffer, 0, (int)s.Length);
using (FileStream fs = new FileStream(configFileName, FileMode.Create))
{
fs.Write(buffer, 0, buffer.Length);
}
}
}
If the only way that Gurok SmartInspect reads configuration information is from a file that you pass it a path to and you've decided to embed that file in your assembly, then yes, your method is fine. You might want to consider adding some exception handling but otherwise I see no problem with this.
I have an image in a C# WPF app whose build action is set to 'Resource'. It's just a file in the source directory, it hasn't been added to the app's resource collection through the drag/drop properties dialog. I'm trying to write it as a stream, but I can't open it despite trying quite a few variations of dots, slashes, namespaces and seemingly everything else.
I can access it to use elsewhere either in xaml with "pack://application:,,,/Resources/images/flags/tr.png", but I can't get at a stream containing it.
Most places seem to say use
using(BinaryReader reader = new BinaryReader(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("ResourceBlenderExpress.Resources.images.flags.tr.png"))) {
using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(imageFile))) {
while((read = reader.Read(buffer, 0, buffer.Length)) > 0) {
writer.Write(buffer, 0, read);
}
writer.Close();
}
reader.Close();
}
Which I haven't had any luck with.
You're probably looking for Application.GetResourceStream
StreamResourceInfo sri = Application.GetResourceStream(new Uri("Images/foo.png"));
if (sri != null)
{
using (Stream s = sri.Stream)
{
// Do something with the stream...
}
}
GetManifestResourceStream is for traditional .NET resources i.e. those referenced in RESX files. These are not the same as WPF resources i.e. those added with a build action of Resource. To access these you should use Application.GetResourceStream, passing in the appropriate pack: URI. This returns a StreamResourceInfo object, which has a Stream property to access the resource's data.
If I get you right, you have a problem to open the resource stream, because you do not know its exact name? If so, you could use
System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames()
to get a list of names of all included resources. This way you can find the resource name that was assignd to your image.
There's no need to call the Close() method, it will be automatically called by Dispose() at the end of the using clause. So your code might look like this:
using(BinaryReader reader = new BinaryReader(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("ResourceBlenderExpress.Resources.images.flags.tr.png")))
using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(imageFile)))
{
while((read = reader.Read(buffer, 0, buffer.Length)) > 0)
{
writer.Write(buffer, 0, read);
}
}