Stream.WriteTo locks up thread - c#

I have this code:
public static void SerializeRO(Stream stream, ReplicableObject ro) {
MemoryStream serializedObjectStream = new MemoryStream();
Formatter.Serialize(serializedObjectStream, ro);
MemoryStream writeStream = new MemoryStream();
BinaryWriter bw = new BinaryWriter(writeStream);
bw.Write(serializedObjectStream.Length);
serializedObjectStream.Seek(0, SeekOrigin.Begin);
serializedObjectStream.WriteTo(writeStream);
serializedObjectStream.Close();
writeStream.WriteTo(stream);
bw.Close();
}
The line writeStream.WriteTo(stream); never finishes. The program gets to that line and won't progress.
stream is always a NetworkStream. I've checked and I think it's a valid object (at least it's not null nor disposed).
So what's going on?

I tried your code - writing to a FileStream - and I always get zero bytes written to the stream. I don't know why WriteTo would block on a NextWorkStream when there's nothing to write, but that could be a problem
When I extract the bytes from the MemoryStream and write them directly to stream everything works e.g. (I'm creating a binary formatter in the routine, it seems you already have a formatter).
public static void SerializeRO(Stream stream, object ro)
{
MemoryStream serializedObjectStream = new MemoryStream();
var f = new BinaryFormatter();
f.Serialize(serializedObjectStream, ro);
MemoryStream writeStream = new MemoryStream();
BinaryWriter bw = new BinaryWriter(writeStream);
var bytes = serializedObjectStream.ToArray();
bw.Write(bytes.Length);
bw.Write(bytes);
var bwBytes = writeStream.ToArray();
stream.Write(bwBytes, 0, bwBytes.Length);
bw.Close();
}
However I'd do it like this with one MemoryStream and writing directly to stream, unless there's something I don't know about NetworkStream (this will of course close stream which may not be what you want)
public static void SerializeRO(Stream stream, object ro)
{
byte[] allBytes;
using (var serializedObjectStream = new MemoryStream())
{
var f = new BinaryFormatter();
f.Serialize(serializedObjectStream, ro);
allBytes = serializedObjectStream.ToArray();
}
using (var bw = new BinaryWriter(stream))
{
bw.Write(allBytes.Length);
bw.Write(allBytes);
}
}
Version that won't close your NetworkStream (just don't put the binary writer in a using statement or Close() it)
public static void SerializeRO(Stream stream, object ro)
{
byte[] allBytes;
using (var serializedObjectStream = new MemoryStream())
{
var f = new BinaryFormatter();
f.Serialize(serializedObjectStream, ro);
allBytes = serializedObjectStream.ToArray();
}
var bw = new BinaryWriter(stream)
bw.Write(allBytes.Length);
bw.Write(allBytes);
}

Just my thoughts: try to close your BinaryWriter before writing stream to another. While your writer is opened stream is not finished and as the result WriteTo newer will find the end of the stream.

Related

Do I need to dispose of StreamWriter when generating a stream from a string?

So I have the following code to convert a string to a MemoryStream https://stackoverflow.com/a/1879470/2987066
public static Stream GenerateStreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
Would it be correct to dispose of the StreamWriter as it implements IDisposable but as we need to return the stream we use the leaveOpen property on the StreamWriter
so would the following be correct to deal with memory leaks or is it not necessary?
public static Stream GenerateStreamFromString(string s)
{
var stream = new MemoryStream();
using(var writer = new StreamWriter(stream, leaveOpen: true))
{
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
}
From the comments. StreamWriter doesnt actually hold any resources itself that need to be disposed of and therefore doesnt need to be wrapped in a using statement.
public static Stream GenerateStreamFromString(string s)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(s);
writer.Flush();
stream.Position = 0;
return stream;
}
As an aside MemoryStream does need disposing of, even if the StreamWriter is wrapped in a using statement.
The Dispose method on StreamWriter just calls Close on the underlying stream

GZIPStream Compression Always Returns 10 Bytes

I'm trying to compress some text in my UWP application. I created this method to make it easier later on:
public static byte[] Compress(this string s)
{
var b = Encoding.UTF8.GetBytes(s);
using (MemoryStream ms = new MemoryStream())
using (GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress))
{
zipStream.Write(b, 0, b.Length);
zipStream.Flush(); //Doesn't seem like Close() is available in UWP, so I changed it to Flush(). Is this the problem?
return ms.ToArray();
}
}
But unfortunately this always returns 10 bytes, no matter what the input text is. Is it because I don't use .Close() on the GZipStream?
You are returning the byte data too early.
The Close() method is replaced by the Dispose() method. So the GZIP stream will be written only when disposed so after you leave the using(GZipStream) {} block.
public static byte[] Compress(string s)
{
var b = Encoding.UTF8.GetBytes(s);
var ms = new MemoryStream();
using (GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress))
{
zipStream.Write(b, 0, b.Length);
zipStream.Flush(); //Doesn't seem like Close() is available in UWP, so I changed it to Flush(). Is this the problem?
}
// we create the data array here once the GZIP stream has been disposed
var data = ms.ToArray();
ms.Dispose();
return data;
}

GZipStream works when writing to FileStream, but not MemoryStream

If compress some json text, and write that it to a file using a FileStream I get the expected results. However, I do not want to write to disk. I simply want to memorystream of the compressed data.
Compression to FileStream:
string json = Resource1.json;
using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json)))
using (FileStream output = File.Create(#"C:\Users\roarker\Desktop\output.json.gz"))
{
using (GZipStream compression = new GZipStream(output, CompressionMode.Compress))
{
input.CopyTo(compression);
}
}
Above works. Below, the output memory stream is length 10 and results in an empty .gz file.
string json = Resource1.json;
using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json)))
using (MemoryStream output = new MemoryStream())
{
using (GZipStream compression = new GZipStream(output, CompressionMode.Compress))
{
input.CopyTo(compression);
byte[] bytes = output.ToArray();
}
}
EDIT:
Moving output.ToArray() outside the inner using clause seems to work. However, this closes the output stream for most usage. IE:
using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json)))
using (MemoryStream output = new MemoryStream())
{
using (GZipStream compression = new GZipStream(output, CompressionMode.Compress))
{
input.CopyTo(compression);
}
WriteToFile(output);
}
where :
public static void WriteToFile(Stream stream)
{
using (FileStream output = File.Create(#"C:\Users\roarker\Desktop\output.json.gz"))
{
stream.CopyTo(output);
}
}
This will fail on stream.CopyTo because the stream has been closed. I know I could make a new Stream from bytes of output.ToArray(), but why is this necessary? why does ToArray() work when the stream is closed?
Final Edit:
Just needed to use the contructor of the GZipStream with the leaveOpen parameter.
You're calling ToArray() before you've closed the GZipStream... that means it hasn't had a chance to flush the final bits of its buffer. This is a common issue for compression an encryption streams, where closing the stream needs to write some final pieces of data. (Even calling Flush() explicitly won't help, for example.)
Just move the ToArray call:
using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json)))
using (MemoryStream output = new MemoryStream())
{
using (GZipStream compression = new GZipStream(output, CompressionMode.Compress))
{
input.CopyTo(compression);
}
byte[] bytes = output.ToArray();
// Use bytes
}
(Note that the stream will be disposed when you call ToArray, but that's okay.)

MemoryStream disables reading when returned

In my program, I am basically reading in a file, doing some processing to it, and then passing it back to the main program as a memorystream, which will be handled by a streamreader. This will all be handled by a class beside my main.
The problem is, when I return the memory stream from my method in another class, the "canread" variable is set to false, and thus causes the streamreader initialization to fail.
Below is an example of the problem happening (though in here I'm writing to the memorystream in the other class, but it still causes the same error when i pass it back.
In the class named "Otherclass":
public static MemoryStream ImportantStreamManipulator()
{
MemoryStream MemStream = new MemoryStream();
StreamWriter writer = new StreamWriter(MemStream);
using (writer)
{
//Code that writes stuff to the memorystream via streamwriter
return MemStream;
}
}
The function calls in the main program:
MemoryStream MStream = Otherclass.ImportantStreamManipulator();
StreamReader reader = new StreamReader(MStream);
When I put a breakpoint on the "return MemStream", the "CanRead" property is still set to true. Once I step such that it gets back to my main function, and writes the returned value to MStream, the "CanRead" property is set to false. This then causes an exception in StreamReader saying that MStream could not be read (as the property indicated). The data is in the streams buffer as it should be, but I just can't get it out.
How do I set it so that "CanRead" will report true once it is returned to my main? Or am I misunderstanding how MemoryStream works and how would I accomplish what I want to do?
This is the problem:
using (writer)
{
//Code that writes stuff to the memorystream via streamwriter
return MemStream;
}
You're closing the writer, which closes the MemoryStream. In this case you don't want to do that... although you do need to flush the writer, and rewind the MemoryStream. Just change your code to:
public static MemoryStream ImportantStreamManipulator()
{
// Probably add a comment here stating that the lack of using statements
// is deliberate.
MemoryStream stream = new MemoryStream();
StreamWriter writer = new StreamWriter(stream);
// Code that writes stuff to the memorystream via streamwriter
writer.Flush();
stream.Position = 0;
return stream;
}
The StreamWriter takes ownership of the memory stream and when the using statement ends, the MemoryStream is also closed.
See Is there any way to close a StreamWriter without closing its BaseStream?.
As others have stated, the problem is that the Stream is closed when the StreamWriter is closed. One possible way to deal with this is to return a byte array rather than a MemoryStream. This avoids having potentially long running objects that must be disposed by the garbage collector.
public static void Main()
{
OutputData(GetData());
}
public static byte[] GetData()
{
byte[] binaryData = null;
using (MemoryStream ms = new MemoryStream())
using (StreamWriter sw = new StreamWriter(ms))
{
string data = "My test data is really great!";
sw.Write(data);
sw.Flush();
binaryData = ms.ToArray();
}
return binaryData;
}
public static void OutputData(byte[] binaryData)
{
using (MemoryStream ms = new MemoryStream(binaryData))
using (StreamReader sr = new StreamReader(ms))
{
Console.WriteLine(sr.ReadToEnd());
}
}
Another method is to copy the Stream to another stream prior to returning. However, this still has the problem that subsequent access to it with a StreamReader will close that stream.
public static void RunSnippet()
{
OutputData(GetData());
}
public static MemoryStream GetData()
{
MemoryStream outputStream = new MemoryStream();
using (MemoryStream ms = new MemoryStream())
using (StreamWriter sw = new StreamWriter(ms))
{
string data = "My test data is really great!";
sw.Write(data);
sw.Flush();
ms.WriteTo(outputStream);
outputStream.Seek(0, SeekOrigin.Begin);
}
return outputStream;
}
public static void OutputData(MemoryStream inputStream)
{
using (StreamReader sr = new StreamReader(inputStream))
{
Console.WriteLine(sr.ReadToEnd());
}
}

Send objects via Sockets

I am new to stocks in C#, I wish to send a Object in C#. Have been using BinaryWriter to send data (works fine for string), but it doesn't seem to have a method like
writer.Writer(new SerliaizedObject());
How do we achieve this using BinaryReader/BinaryWriter
UPDATE:
I used the following functions to convert by object to byte and send it across to the client
public static byte[] SerializeToBytes<T>(T item)
{
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, item);
stream.Seek(0, SeekOrigin.Begin);
return stream.ToArray();
}
}
public static object DeserializeFromBytes(byte[] bytes)
{
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream(bytes))
{
return formatter.Deserialize(stream);
}
}
To send the data is used:
formatter = new BinaryFormatter();
MessageBox.Show(SerializeToBytes<mydata>(new mydata()).Length+"");
writer.Write(SerializeToBytes<mydata>(new mydata()));
ChatBox.AppendText("Client Says :" + UserMessage.Text + "\r\n");
And to read the data I used:
while (true)
{
byte[] bytes = reader.ReadBytes(120);
mydata temp = DeserializeFromBytes(bytes) as mydata;
ChatBox.AppendText("Server Says " + temp + "\r\n");
}
But the reader doesn't seem to work, Any Ideas?
Use BinaryFormatter to write serializable objects to streams in binary format:
FileStream fs = new FileStream("DataFile.dat", FileMode.Create);
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, mySerializable);
You should use the first 4 bytes as length header, and in the receive loop you add a variable bytesReadSoFar. Then you know when everything is received.

Categories

Resources