Writing to MemoryStream not working as expected - c#

I'm using the DryWetMidi library to process some MIDI data.
First I get the MIDI Data as a MemoryStream from the Clipboard:
MemoryStream ms = (MemoryStream)Clipboard.GetDataObject().GetData("Standard MIDI File");
MidiFile mid = MidiFile.Read(ms);
Then I do some stuff with the midi:
mid.RemoveNotes(n => n.NoteName == NoteName.FSharp);
Now I want to write it back to the Clipboard. I managed to do this like this:
using (FileStream file = new FileStream("file.mid", FileMode.Create, FileAccess.
{
mid.Write(file);
}
using (MemoryStream ms2 = new MemoryStream())
using (FileStream file = new FileStream("file.mid", FileMode.Open, FileAccess.Read))
{
byte[] bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
ms2.Write(bytes, 0, (int)file.Length);
Clipboard.Clear();
Clipboard.SetData(midiFormat, ms2);
}
File.Delete("file.mid");
As you can see, first I write the MIDI to a file, then I read that file into a MemoryStream which I then write into the Clipboard. This makes not much sense, because it would be simpler to write it to a MemoryStream directly. Also, I don't want to write a file to the users file system. But there's the problem. I tried it like this:
using (MemoryStream ms2 = new MemoryStream())
{
mid.Write(ms2);
}
This doesn't give me an error, but the MemoryStream is completely empty. Calling ms2.Length results in a System.ObjectDisposedException.
How can I write the midi directly into the MemoryStream?
EDIT: Here's the link to the DryWetMidi Write() Method.
Second Edit: Here's a piece of code that won't work:
MemoryStream ms = (MemoryStream)Clipboard.GetDataObject().GetData(midiFormat);
MidiFile mid = MidiFile.Read(ms);
mid.RemoveNotes(n => n.NoteName == NoteName.FSharp);
MemoryStream ms2 = new MemoryStream();
mid.Write(ms2);
var T = ms2.Length; //This will throw an exception
Third Edit: I am 100% sure that the code posted is exactly the same I'm running. Here's the StackTrace. (Gist because formatting was terrible on SO).

As far as I can see, DryWetMidi uses BinaryWriter to write to stream. And the default behaviour of BinaryWriter is that when it is disposed, It'll dispose the stream as well.
You can't read from MemoryStream when it's disposed but you can call ToArray().
byte[] result;
using (MemoryStream ms2 = new MemoryStream())
{
mid.Write(ms2);
result = ms2.ToArray();
}

Related

How to return an image as an IActionResult from an Image/Bitmap object

I am generating a Barcode image using the barcodelib library + the System.Drawing.Common package available in .Net Core.
I want to return the image to the users in their browser as a plain image (or as a download) but I seem to not find a good way to do so.
What I've tried:
var barcode = new Barcode().Encode(TYPE.CODE128, reference);
usuing (var outputStream = new MemoryStream())
{
barcode.Save(outputStream, ImageFormat.Jpeg);
outputStream.Seek(0, SeekOrigin.Begin);
return File(outputStream, "image/jpeg");
}
This gives an exception, saying that the stream is closed.
It can be fixed by removing the using but isn't it bad? doesn't the streams stay in memory?
Remove the using block on the outputStream. The stream is being closed/disposed before it can be used by the response.
The FileResult will close the stream when it is finished using it.
var barcode = new Barcode().Encode(TYPE.CODE128, reference);
var outputStream = new MemoryStream();
barcode.Save(outputStream, ImageFormat.Jpeg);
outputStream.Seek(0, SeekOrigin.Begin);
return File(outputStream, "image/jpeg");
While FileResult will close the stream, frankly, I don't like depending on some external thing cleaning up after me, and at least to my eyes, the code just looks wrong newing up a MemoryStream outside of a using block and just letting it go without ever explicitly closing it.
There's an overload of File that accepts a byte array, so you can simply move your return outside of your using block.
byte[] bytes;
using (var ms = new MemoryStream())
{
var barcode = new Barcode().Encode(TYPE.CODE128, reference);
barcode.Save(ms, ImageFormat.Jpeg);
bytes = ms.ToArray();
}
return File(bytes, "image/jpeg");
It's a bit of personal preference, admittedly, but that just looks cleaner and more "correct" to me.

GZipStream compression not working

I'm trying to read in a file and compress it using GZipStream, like this:
using (var outStream = new MemoryStream())
{
using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
using (var gzipStream = new GZipStream(outStream, CompressionMode.Compress))
{
fileStream.CopyTo(gzipStream);
Debug.WriteLine(
"Compressed from {0} to {1} bytes",
fileStream.Length,
outStream.Length);
// "outStream" is utilised here (persisted to a NoSql database).
}
}
}
The problem is that outStream.Length always shows 10 bytes. What am I doing wrong?
I've tried calling gzipStream.Close() after the fileStream.CopyTo line (as suggested in other forums) but this seems to close outStream too, so the subsequent code that uses it falls over.
MSDN says: The write operation might not occur immediately but is buffered until the buffer size is reached or until the Flush or Close method is called.
In other words, the fact that all the Write operations are done doesn't mean the data is already in the MemoryStream. You have to do gzipStream.Flush() or close the gzipStream first.
Example:
using (var outStream = new MemoryStream())
{
using (var fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
using (var gzipStream = new GZipStream(outStream, CompressionMode.Compress))
{
fileStream.CopyTo(gzipStream);
}
Debug.WriteLine(
"Compressed from {0} to {1} bytes",
fileStream.Length,
outStream.Length);
// "outStream" is utilised here (persisted to a NoSql database).
}
}
Also, ideally, put it outside of the FileStream as well - you want to close files as soon as you can, rather than waiting for some other processing to finish.

Cannot write to MemoryStream using BinaryWriter

I've tried this code:
byte[] someData = new byte[] { 1, 2, 3, 4 };
MemoryStream stream = new MemoryStream(someData, 1, someData.Length - 1, true);
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(1);
}
stream.Dispose();
Everytime it's run, a NotSupportedException is thrown, telling me that the stream cannot be written to. Why is this the case? The last parameter of the initialization shown in line 2 clearly is true, so I should be able to write to the stream.
It works if I don't specify the start index and count.
Why does this happen?
Always (almost always) create a memory stream without parameters in the constructor:
using (MemoryStream stream = new MemoryStream())
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(1);
}
stream.Flush();
byte[] bytes = stream.GetBuffer();
//use it
}
This code works fine
From MSDN:
Initializes a new non-resizable instance of the MemoryStream class
based on the specified region of a byte array, with the CanWrite
property set as specified.
The BinaryWriter starts writing at the end of the stream, so it needs to resize it to be able to write, but this is not allowed. You can only write to the already allocated bytes of the stream.

unable to save dynamically created MemoryStream with rebex sftp

I'm using StreamWriter to generate a dynamic file and holding it in a MemoryStream. Everything appears to be alright until I go to save the file using rebex sftp.
The example they give on their site works fine:
// upload a text using a MemoryStream
string message = "Hello from Rebex FTP for .NET!";
byte[] data = System.Text.Encoding.Default.GetBytes(message);
System.IO.MemoryStream ms = new System.IO.MemoryStream(data);
client.PutFile(ms, "message.txt");
However the code below does not:
using (var stream = new MemoryStream())
{
using (var writer = new StreamWriter(stream))
{
writer.AutoFlush = true;
writer.Write("test");
}
client.PutFile(stream, "test.txt");
}
The file "test.txt" is saved, however it is empty. Do I need to do more than just enable AutoFlush for this to work?
After writing to the MemoryStream, the stream is positioned at the end. The PutFile method reads from the current position to the end. That's exactly 0 bytes.
You need to position the stream at the beginning before passing it to PutFile:
...
}
stream.Seek(0, SeekOrigin.Begin);
client.PutFile(stream, "test.txt");
You may also need to prevent the StreamWriter from disposing the MemoryStream:
var writer = new StreamWriter(stream);
writer.Write("test");
writer.Flush();
stream.Seek(0, SeekOrigin.Begin);
client.PutFile(stream, "test.txt");

create file and save to it using memorystream

How can i create a file and write to it using the memory stream?
I need to use the memorystream to prevent other threads from trying to access the file.
The data i'm trying to save to a file is html.
How can this be done?
(Presuming you mean how to copy a file's content to a memory stream)
If you are using framework 4:
var memoryStream = new MemoryStream();
using var fileStream = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
fileStream.CopyTo(memoryStream);
Here are code to create file
byte[] data = System.Text.Encoding.ASCII.GetBytes("This is a sample string");
System.IO.MemoryStream ms = new System.IO.MemoryStream();
ms.Write(data, 0, data.Length);
ms.Close();

Categories