I wrote some code in a console program and tested with files.
Now I want to port it to a BizTalk Pipeline Component that implements a specific interface. I wasn't aware that that .Write and .WriteLine methods from a File to a Memory Stream were so different. I thought I would just be able to swap my objects. There is no .WriteLine method, and the .Write method requires offset and bytes (additional parameters).
So now, what is the best way to change my tested code to write to the memory stream, given that I have a lot of .WriteLine statements. I could write to a StringBuffer first, but then I think that would blow the concept of streaming (i.e. would have the whole document in memory at one time).
// This is how I used the streams in the Console program
//FileStream originalStream = File.Open(inFilename, FileMode.Open);
//StreamWriter streamToReturn = new StreamWriter(outFilename);
// This is how to get the input stream in the BizTalk Pipeline Componenet
System.IO.Stream originalStream = pInMsg.BodyPart.GetOriginalDataStream();
MemoryStream streamToReturn = new MemoryStream();
streamToReturn.WriteLine("<" + schemaStructure.rootElement + ">");
There's a lot more code not shown here. Above is just to set the stage for what I did.
Use a StreamWriter which you can use to call WriteLine.
MemoryStream streamToReturn = new MemoryStream();
var writer = new StreamWriter(streamToReturn);
writer.WriteLine("<" + schemaStructure.rootElement + ">");
Related
So I need the ability to encrypt/decrypt the same settings XML file in my application. I can only find examples that use a seperate output file. I don't need an output file. Nothing super secure. I just basically need to make the settings file not readable to protect a couple connections strings. I am able to encrypt the file just fine using this code:
public static void EncryptAndSerialize(Object obj)
{
UnicodeEncoding aUE = new UnicodeEncoding();
byte[] key = aUE.GetBytes("password");
RijndaelManaged RMCrypto = new RijndaelManaged();
using (FileStream fs = File.Open(#"D:\Sample.xml", FileMode.Create))
{
using (CryptoStream cs = new CryptoStream(fs, RMCrypto.CreateEncryptor(key, key), CryptoStreamMode.Write))
{
XmlSerializer xmlser = new XmlSerializer(obj.GetType());
xmlser.Serialize(cs, obj);
}
fs.Close();
}
I just need to know how to use this same sort of process to decrypt that same file. If anyone could point me in the right direction it would be much appreciated. Keep in mind ultra security is not an issue. Forgive my ignorance this task is new to me.
What he said plus...
MemoryStream...
https://msdn.microsoft.com/en-us/library/system.io.memorystream(v=vs.110).aspx
using (var sink = new MemoryStream())
{
// Write your encyphered data to the sink
// (from your FileStream, via the encryption provider)
// and then later, read (or copy) from sink back into
// the FileStream. Don't forget to re-position your
// FileStream before doing so.
}
If it were me I'd use two independent FileStreams. One for read only and, later, another one for writing back to the .xml file (that you just read from). I'd only bother constructing and writing the later if and only if I knew I had a fully formed/filled sink.
You might also investigate the use of SecureString (but I'm digressing):
https://msdn.microsoft.com/en-us/library/system.security.securestring(v=vs.110).aspx
All that said, you NEVER want to directly overwrite a file (i.e., in place edit). If you do, and the write fails (part way through) your original file will be, well, corrupt. Leaving you with zip/nadda/crap. Always write to a new, temp file and only after that completes 100% do you promote the temp file to the source path (typically via FileInfo.MoveTo).
https://msdn.microsoft.com/en-us/library/system.io.fileinfo.moveto(v=vs.110).aspx
If bad stuff happens along the way (and it will!!!), all you do is delete the temp file (off of a catch block, etc.) and you're back where you started from.
The humans won't know that you actually worked two files (and if you have some monitor automation that is getting tripped up by tandem files then rewrite it cause it's well, crap).
Something like this. Notice that this calls CreateDecryptor with the CryptoStreamMode.Read flag telling it to read from the stream.
var decryptor = new RijndaelManaged ();
var transformer = decryptor.CreateDecryptor(_decryptKey, _decryptSeed);
var cryptoStream = new CryptoStream(encryptedStream, transformer, CryptoStreamMode.Read);
cryptoStream.CopyTo(resultStream);
resultStream.Close();
Some editorial comments:
1) AES would be better and here's why:
https://blogs.msdn.microsoft.com/shawnfa/2006/10/09/the-differences-between-rijndael-and-aes/
2) Don't underestimate .net encryption - Microsoft doesn't fool around
3) Bad encryption can be worse than no encryption because it provides a false sense of security
A helper method to turn a string into a zipped up text file:
public static System.Net.Mail.Attachment CreateZipAttachmentFromString(string content, string filename)
{
using (MemoryStream memoryStream = new MemoryStream())
{
using (ZipArchive zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Update))
{
ZipArchiveEntry zipArchiveEntry = zipArchive.CreateEntry(filename);
using (StreamWriter streamWriter = new StreamWriter(zipArchiveEntry.Open()))
{
streamWriter.Write(content);
}
}
MemoryStream memoryStream2 = new MemoryStream(memoryStream.ToArray(), false);
return new Attachment(memoryStream2, filename + ".zip", MediaTypeNames.Application.Zip);
}
}
I was really hoping to avoid turning the first memory stream into an array, making another memory stream on it to read it, and passing that to attachment. My logic was, why copy X megabytes to another place in memory to establish another stream pointing to the copy, when it's essentially just what we started out with.. It's the multi-megabyte equivalent of redundancy like if(myBool == true)
So I figured instead I would Seek back to the start of the first memory stream, and then attachment could just read that.. Or I would establish another memorystream pointing to the buffer of the first, and with the offset and length parameters set so it would know what to read
Neither of these approaches work out because it seems that ZipArchive only pushes data into the memory stream (in my case maybe) when control falls out of the using block and the ziparchive is disposed. Disposing it also disposes the MemoryStream and nearly everything (other than ToArray() and GetBuffer()) throw ObjectDisposedException.
Ultimately I can't seek it or get its length after the ZipArchive pumps data into it and before it pumps it in, the offset is usually zero and the length is definitely zero so the values are useless
Is there a nice optimal way, short of configuring my own over-large buffer (which then makes it non expandable by MemoryStream), to avoid having to burn up around 2x the memory bytes of the archive size with this method?
Most well designed streams and stream-users in .NET have an additional boolean parameter that can be used to instruct them to leave the "base stream" (terrible name) open when disposing.
This is ZipArchive's constructor:
public ZipArchive(
Stream stream,
ZipArchiveMode mode,
bool leaveOpen
)
There is no need for a second MemoryStream. You need to do two things:
Ensure, that the MemoryStream is not disposed before the last usage point. This is harmless. Disposing a MemoryStream does nothing helpful and for compatibility reasons can never do anything in the future. The .NET Framework has a very high compatibility bar. They often don't even dare to rename fields.
Seek to offset zero.
So remove the using around the MemoryStream and use the ctor for ZipArchive that allows you to leave the stream open.
Since the Attachment you are returning makes use of the MemoryStream you can't dispose it before exiting the method. Again, this is harmless. The only negative point is that the code becomes less obvious.
There's an entirely different approach: You can write your own Stream class that creates the bytes on demand. That way there is no need to buffer the string and ZIP bytes at all. This is much more work, of course. And it does not detract from the fact that the whole string must sit in memory at once, so it's still not a O(1) space solution.
public static System.Net.Mail.Attachment CreateZipAttachmentFromString(string content, string filename)
{
MemoryStream memoryStream = new MemoryStream();
using (ZipArchive zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Update, true))
{
ZipArchiveEntry zipArchiveEntry = zipArchive.CreateEntry(filename);
using (StreamWriter streamWriter = new StreamWriter(zipArchiveEntry.Open()))
{
streamWriter.Write(content);
}
}
memoryStream.Position = 0;
return new Attachment(memoryStream, filename + ".zip", MediaTypeNames.Application.Zip);
}
I want to write a String to a Stream (a MemoryStream in this case) and read the bytes one by one.
stringAsStream = new MemoryStream();
UnicodeEncoding uniEncoding = new UnicodeEncoding();
String message = "Message";
stringAsStream.Write(uniEncoding.GetBytes(message), 0, message.Length);
Console.WriteLine("This:\t\t" + (char)uniEncoding.GetBytes(message)[0]);
Console.WriteLine("Differs from:\t" + (char)stringAsStream.ReadByte());
The (undesired) result I get is:
This: M
Differs from: ?
It looks like it's not being read correctly, as the first char of "Message" is 'M', which works when getting the bytes from the UnicodeEncoding instance but not when reading them back from the stream.
What am I doing wrong?
The bigger picture: I have an algorithm which will work on the bytes of a Stream, I'd like to be as general as possible and work with any Stream. I'd like to convert an ASCII-String into a MemoryStream, or maybe use another method to be able to work on the String as a Stream. The algorithm in question will work on the bytes of the Stream.
After you write to the MemoryStream and before you read it back, you need to Seek back to the beginning of the MemoryStream so you're not reading from the end.
UPDATE
After seeing your update, I think there's a more reliable way to build the stream:
UnicodeEncoding uniEncoding = new UnicodeEncoding();
String message = "Message";
// You might not want to use the outer using statement that I have
// I wasn't sure how long you would need the MemoryStream object
using(MemoryStream ms = new MemoryStream())
{
var sw = new StreamWriter(ms, uniEncoding);
try
{
sw.Write(message);
sw.Flush();//otherwise you are risking empty stream
ms.Seek(0, SeekOrigin.Begin);
// Test and work with the stream here.
// If you need to start back at the beginning, be sure to Seek again.
}
finally
{
sw.Dispose();
}
}
As you can see, this code uses a StreamWriter to write the entire string (with proper encoding) out to the MemoryStream. This takes the hassle out of ensuring the entire byte array for the string is written.
Update: I stepped into issue with empty stream several time. It's enough to call Flush right after you've finished writing.
Try this "one-liner" from Delta's Blog, String To MemoryStream (C#).
MemoryStream stringInMemoryStream =
new MemoryStream(ASCIIEncoding.Default.GetBytes("Your string here"));
The string will be loaded into the MemoryStream, and you can read from it. See Encoding.GetBytes(...), which has also been implemented for a few other encodings.
You're using message.Length which returns the number of characters in the string, but you should be using the nubmer of bytes to read. You should use something like:
byte[] messageBytes = uniEncoding.GetBytes(message);
stringAsStream.Write(messageBytes, 0, messageBytes.Length);
You're then reading a single byte and expecting to get a character from it just by casting to char. UnicodeEncoding will use two bytes per character.
As Justin says you're also not seeking back to the beginning of the stream.
Basically I'm afraid pretty much everything is wrong here. Please give us the bigger picture and we can help you work out what you should really be doing. Using a StreamWriter to write and then a StreamReader to read is quite possibly what you want, but we can't really tell from just the brief bit of code you've shown.
I think it would be a lot more productive to use a TextWriter, in this case a StreamWriter to write to the MemoryStream. After that, as other have said, you need to "rewind" the MemoryStream using something like stringAsStream.Position = 0L;.
stringAsStream = new MemoryStream();
// create stream writer with UTF-16 (Unicode) encoding to write to the memory stream
using(StreamWriter sWriter = new StreamWriter(stringAsStream, UnicodeEncoding.Unicode))
{
sWriter.Write("Lorem ipsum.");
}
stringAsStream.Position = 0L; // rewind
Note that:
StreamWriter defaults to using an instance of UTF8Encoding unless specified otherwise. This instance of UTF8Encoding is constructed without a byte order mark (BOM)
Also, you don't have to create a new UnicodeEncoding() usually, since there's already one as a static member of the class for you to use in convenient utf-8, utf-16, and utf-32 flavors.
And then, finally (as others have said) you're trying to convert the bytes directly to chars, which they are not. If I had a memory stream and knew it was a string, I'd use a TextReader to get the string back from the bytes. It seems "dangerous" to me to mess around with the raw bytes.
You need to reset the stream to the beginning:
stringAsStream.Seek(0, SeekOrigin.Begin);
Console.WriteLine("Differs from:\t" + (char)stringAsStream.ReadByte());
This can also be done by setting the Position property to 0:
stringAsStream.Position = 0
I am attempting to write an audio file as a .wav in a memorystream out to the response so the client can download it. It looks like on client side when trying to open the file it has a ".partial" extension. It is almost as if the file is not getting released to the client.
The below is my code... Attempting to write the bytes directly to the local machine works fine (you will see that code commented out).
// Initialize a new instance of the speech synthesizer.
using (SpeechSynthesizer synth = new SpeechSynthesizer())
using (MemoryStream stream = new MemoryStream())
{
// Create a SoundPlayer instance to play the output audio file.
MemoryStream streamAudio = new MemoryStream();
// Configure the synthesizer to output to an audio stream.
synth.SetOutputToWaveStream(streamAudio);
synth.Speak("This is sample text-to-speech output. How did I do?");
streamAudio.Position = 0;
// Set the synthesizer output to null to release the stream.
synth.SetOutputToNull();
// Insert code to persist or process the stream contents here.
// THIS IS NOT WORKING WHEN WRITING TO THE RESPONSE, .PARTIAL FILE CREATED
Response.Clear();
Response.ContentType = "audio/wav";
Response.AppendHeader("Content-Disposition", "attachment; filename=mergedoutput.wav");
Response.BinaryWrite(streamAudio.GetBuffer());
Response.Flush();
// THIS WORKS WRITING TO A FILE
//System.IO.File.WriteAllBytes("c:\\temp\\als1.wav", streamAudio.GetBuffer());
}
MemoryStream.GetBuffer is not the correct method to call:
Note that the buffer contains allocated bytes which might be unused.
For example, if the string "test" is written into the MemoryStream
object, the length of the buffer returned from GetBuffer is 256, not
4, with 252 bytes unused. To obtain only the data in the buffer, use
the ToArray method; however, ToArray creates a copy of the data in
memory.
so use MemoryStream.ToArray instead:
Response.BinaryWrite(streamAudio.ToArray());
Looks like the issue was the fact the speak method needs to be run on its own thread. The following provides the solution to get back the byte array properly and then be able to write that to the response.
C# SpeechSynthesizer makes service unresponsive
I need to create a large text document. I currently use StringBuilder to make the document and then call File.WriteallText(filename,sb.ToString). Unfortunately, this is now starting to throw out of memory exceptions.
Is there a better way to stream a StringBuilder to file or is there some other technique I should be using?
Instead of using StringBuilder, try using TextWriter (which has a broadly similar API, but which can write to a number of underlying destinations, including files) - i.e.
using(TextWriter writer = File.CreateText(path))
{
// loop etc
writer.Write(...);
}
More generally, it is worth separating the code that knows about files from the code that knows about how to write the data, i.e.
using(var writer = File.CreateText(path))
{
Serialize(writer);
}
...
void Serialize(TextWriter writer)
{
...
}
this makes it easier to write to different targets. For example, you can now do in-memory too:
var sw = new StringWriter();
Serialize(sw);
string text = sw.ToString();
The point being: your Serialize code didn't need to change to accomodate a different target. This could also be writing directly to a network, or writing through a compression/encryption stream. Very versatile.
Just use a StreamWriter that writes to a FileStream:
using (StreamWriter writer = new StreamWriter("filename.txt")) {
...
}
This will of course mean that you can't change the text that is already written, like you can do in a StringBuilder, but I assume that you are not using that anyway.
Why not streaming directly into the stream?
You could use the TextWriter.
You can use StreamWriter and write to the file directly.