MemoryStream expandable with initial buffer - c#

I am trying to load some filestream into a memorystream. The source stream could be any stram, but the focus here is the destination stream.
The source has more than 3Gb.
I tryed 4 different approaches to this.
1)fDest = new MemoryStream(); and then read 4K blocks into this. This takes forever com complete as the buffer must be resized on every step.
2)fDest = new MemoryStream(int.MaxValue); Got OutOfMemoryException on creation
3)fDest = new MemoryStream(1073741823); and then read 4K blocks into this. This loads fast but i get an OutOfMemory exception when the buffer needs to be resized.
4)fDest = new MemoryStream(1073741824);and then read 4K blocks into this. This works. The buffer resize is ok.
Can anyone point me some direction on why i got this behaviour with just one byte in diference on buffer size? I

Related

c# after copying stream it wont work anymore

If I did this in my MAUI project:
var uploadImage = new UploadImage();
var img = await uploadImage.OpenMediaPickerAsync();
var imagefile = await uploadImage.Upload(img);
var imageBytes = uploadImage.StringToByteBase64(imagefile.byteBase64);
var stream = uploadImage.ByteArrayToStream(imageBytes);
img_profilePic.Source = ImageSource.FromStream(() => stream); //working
I am displaying an image from my ios simulator. At one point in time I have the stream of the IO at my displosal.
If I now add
MemoryStream newStream = new MemoryStream();
stream.CopyTo(newStream);
these two lines of code to my code above, the image I was displaying at that point dissapears.
SO somehow, when I copy my stream, I for some reason also delete the already existing stream...?
What is going on here...
The point of streams is to be able to process very large amounts of data (sequentially) without having to load all that data into memory (at once anyway), which is what happens if instead of streams you work with collections. So, what stream do is track the current position so they can keep loading more data to memory when the position moves forward and unload already processed data. So, using the same stream for two things it's not going to work because the second usage won't get the data that the first usage has already consumed.
That said, it's possible to reset the position of a stream with the seek operation (as long as the type of stream you are using allows it).
Check out this answer https://stackoverflow.com/a/1746108/352826
SO somehow, when I copy my stream, I for some reason also delete the already existing stream...?
It's far more likely that you're trying to use the same stream as multiple sources without rewinding it. Streams have a position that increases as you use it.
In short, use this when you want to reuse your stream:
stream.Position = 0;
Assuming, of course, that whatever stream you're using is rewindable in the first place. If not, then copy it to a memory stream first and reuse that as many times as you wish, rewinding between uses.

Need for a fast writing of binary data to a file

I receive a fair amount of binary data from an external device, about 30-40 MB/s. I need to save it to a file. On the external source device side, I have a very small buffer that I can't enlarge and as soon as the transmission stutters on the C# application side, it quickly gets clogged and I lose data.
In the application, I tried writing using FileStream, but unfortunately it is not fast enough.
_FileStream = new FileStream(FileName, FileMode.Create, FileAccess.Write);
...
void Handler_OnFtdiBytesReceived(object sender, FtdiBytesReceivedEventArgs e)
{
...
Array.Copy(e.Bytes, 0, _ReceivedDataBuffer, _ReceivedDataBufferPosition, e.NumBytesAvailable);
_ReceivedDataBufferPosition += (int)e.NumBytesAvailable;
if (_ReceivedDataBufferPosition > 0)
{
_FileStream.Write(_ReceivedDataBuffer, 0, (int)e.NumBytesAvailable);
_ReceivedDataBufferPosition = 0;
}
if (_IsOperationFinished == true)
{
_FileStream.Flush();
_FileStream.Close();
}
...
}
I also tried adding a BinaryWriter:
_FileStream = new FileStream(FileName, FileMode.Create, FileAccess.Write);
_BinaryWriter = new BinaryWriter(_FileStream);
and then:
_BinaryWriter.Write(_ReceivedDataBuffer, 0, (int)e.NumBytesAvailable);
instead of previous _FileStream.Write(...), but also the buffer on the transmit side gets clogged.
Is there any way to deal with this?
I wonder if it might help to somehow buffer the data in the computer's RAM when receiving it and, for example, when it reaches some sizable amount (say, 512 MB), start writing to the file in a separate Task, so that in the meantime, new data can be collected into the buffer continuously. Perhaps I would need to use two buffers and use them alternately, one to receive data continuously and the other from which to write to the file, and swap??
This seems quite complex code for someone with little experience, which I don't know if it will help, so I'd like to ask you for a hint first.
I'll just add at the end that I have the ability to watch the buffer fill up in this external device and by commenting out this one line regarding writing:
_FileStream.Write(_ReceivedDataBuffer, 0, (int)e.NumBytesAvailable);
I see that the problem with its clogging disappears. Earlier I also analyzed whether other code fragments might be inefficient, such as Array.Copy(...) or passing parameters via Event, but it had no effect.

MediaElement randomly stops playing audio from MemoryStream

In my Silverlight application, I read audio data from a File with a ZipInputStream, then store it in a MemoryStream. Here's the code I'm using:
byte[] buf = new byte[1024];
MemoryStream memoryStream = new MemoryStream();
int len;
while ((len = zipInputStream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buf, 0, len);
}
// Reset the position for reading.
memoryStream.Position = 0;
// Check how large the byte[] is.
textBox.Text = memoryStream.ToArray().Length.ToString();
MediaElement me = new MediaElement();
me.setSource(memoryStream);
me.Play();
This code partly works; the song from the input file starts playing. In addition, the byte[] always has the same length for the same song. I take this to mean that the song is being completely read each time.
However, my problem is that the audio randomly stops playing at a different point each run through. The song has not yet fully played, either. I'm not exactly sure why this happens.
If anyone knows, I'd like to know why this is happening. I'd also like to know if there's something wrong with my code, or if there's a different way I should go about storing the audio (that doesn't involve storing a file on the user's computer).
I was finally able to find a solution. By making the MediaElement and MemoryStream global variables, the song played through completely each time. I'm still not 100% sure what caused this error, although my best guess is that the problem was caused by the garbage collector deleting the stream.

C# .NET: Will a BinaryWriter flush when the FileStream buffer is filled?

I'm coming across something trivial, but it appears that data is flushed to disk (out of the FileStream's buffer) when the data I'm buffering hits the size of the FileStream's buffer.
//use the FileStream buffer to actually buffer the data to be written, so segments are written as desired.
FileStream writeStream = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.None, CommandOperationBufferSize);
BinaryWriter binWriter = new BinaryWriter(writeStream);
byte[] FullSize = new byte[CommandOperationTotalSize];
//the BinaryWriter will flush when the FileStream buffer is hit
binWriter.Write(FullSize); //DATA FLUSHES TO DISK HERE!
//if wait, wait five seconds
if (CommandOperation == "writewait" || CommandOperation == "appendwait")
{
Thread.Sleep(5000);
writeStream.Flush();
Thread.Sleep(5000);
}
writeStream.Close();
writeStream.Dispose();
binWriter.Close();
Can anyone confirm that this is the case? That the FileStream's buffer is actual .Flush() when the FileStream's buffer is filled?
I ask because it appears that if I set CommandOperationTotalSize to 1MB, and set the CommandOperationBufferSize to 64KB, data is flushed to disk when the buffer is filled.
Sounds like I answered my own question, but it seems odd that the FileStream buffer wouldn't just overflow? But maybe the API developers are trying to be nice?
Thanks,
Matt
You can readily assume that overflowing the buffer is not possible. The class would be rather hard to use if that was the case, given that FileStream has no properties at all to tell you how much is currently being buffered.
The buffer is only there to reduce the number of calls to the native Windows WriteFile() call. Important when you write small amounts of data, say one byte at a time. If you don't explicitly specify the buffer size then it will use a buffer of 4096 bytes. Which is fine, it is very rare to need something else. Any writes are further buffered by the file system cache. You should only consider a non-standard size when you use FileOptions.WriteThrough

Stream Reuse in C#

I've been playing around with what I thought was a simple idea. I want to be able to read in a file from somewhere (website, filesystem, ftp), perform some operations on it (compress, encrypt, etc.) and then save it somewhere (somewhere may be a filesystem, ftp, or whatever). It's a basic pipeline design. What I would like to do is to read in the file and put it onto a MemoryStream, then perform the operations on the data in the MemoryStream, and then save that data in the MemoryStream somewhere. I was thinking I could use the same Stream to do this but run into a couple of problems:
Everytime I use a StreamWriter or StreamReader I need to close it and that closes the stream so that I cannot use it anymore. That seems like there must be some way to get around that.
Some of these files may be big and so I may run out of memory if I try to read the whole thing in at once.
I was hoping to be able to spin up each of the steps as separate threads and have the compression step begin as soon as there is data on the stream, and then as soon as the compression has some compressed data available on the stream I could start saving it (for example). Is anything like this easily possible with the C# Streams? ANyone have thoughts as to how to accomplish this best?
Thanks,
Mike
Using a helper method to drive the streaming:
static public void StreamCopy(Stream source, Stream target)
{
byte[] buffer = new byte[8 * 1024];
int size;
do
{
size = source.Read(buffer, 0, 8 * 1024);
target.Write(buffer, 0, size);
} while (size > 0);
}
You can easily combine whatever you need:
using (FileStream iFile = new FileStream(...))
using (FileStream oFile = new FileStream(...))
using (DeflateStream oZip = new DeflateStream(outFile, CompressionMode.Compress))
StreamCopy(iFile, oZip);
Depending on what you are actually trying to do, you'd chain the streams differently. This also uses relatively little memory, because only the data being operated upon is in memory.
StreamReader/StreamWriter shouldn't have been designed to close their underlying stream -- that's a horrible misfeature in the BCL. But they do, they won't be changed (because of backward compatibility), so we're stuck with this disaster of an API.
But there are some well-established workarounds, if you want to use StreamReader/Writer but keep the Stream open afterward.
For a StreamReader: don't Dispose the StreamReader. It's that simple. It's harmless to just let a StreamReader go without ever calling Dispose. The only effect is that your Stream won't get prematurely closed, which is actually a plus.
For a StreamWriter: there may be buffered data, so you can't get away with just letting it go. You have to call Flush, to make sure that buffered data gets written out to the Stream. Then you can just let the StreamWriter go. (Basically, you put a Flush where you normally would have put a Dispose.)
Unless you're reading in streams bigger than your hard drive, I don't think you'll run out of memory:
http://blogs.msdn.com/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx

Categories

Resources