Can I close a file stream without calling Flush (in C#)? I understood that Close and Dispose calls the Flush method first.
MSDN is not 100% clear, but Jon Skeet is saying "Flush", so do it before close/dispose. It won't hurt, right?
From FileStream.Close Method:
Any data previously written to the buffer is copied to the file before
the file stream is closed, so it is not necessary to call Flush before
invoking Close. Following a call to Close, any operations on the file
stream might raise exceptions. After Close has been called once, it
does nothing if called again.
Dispose is not as clear:
This method disposes the stream, by writing any changes to the backing
store and closing the stream to release resources.
Remark: the commentators might be right, it's not 100% clear from the Flush:
Override Flush on streams that implement a buffer. Use this method to
move any information from an underlying buffer to its destination,
clear the buffer, or both. Depending upon the state of the object, you
might have to modify the current position within the stream (for
example, if the underlying stream supports seeking). For additional
information see CanSeek.
When using the StreamWriter or BinaryWriter class, do not flush the
base Stream object. Instead, use the class's Flush or Close method,
which makes sure that the data is flushed to the underlying stream
first and then written to the file.
TESTS:
var textBytes = Encoding.ASCII.GetBytes("Test123");
using (var fileTest = System.IO.File.Open(#"c:\temp\fileNoCloseNoFlush.txt", FileMode.CreateNew))
{
fileTest.Write(textBytes,0,textBytes.Length);
}
using (var fileTest = System.IO.File.Open(#"c:\temp\fileCloseNoFlush.txt", FileMode.CreateNew))
{
fileTest.Write(textBytes, 0, textBytes.Length);
fileTest.Close();
}
using (var fileTest = System.IO.File.Open(#"c:\temp\fileFlushNoClose.txt", FileMode.CreateNew))
{
fileTest.Write(textBytes, 0, textBytes.Length);
fileTest.Flush();
}
using (var fileTest = System.IO.File.Open(#"c:\temp\fileCloseAndFlush.txt", FileMode.CreateNew))
{
fileTest.Write(textBytes, 0, textBytes.Length);
fileTest.Flush();
fileTest.Close();
}
What can I say ... all files got the text - maybe this is just too little data?
Test2
var rnd = new Random();
var size = 1024*1024*10;
var randomBytes = new byte[size];
rnd.NextBytes(randomBytes);
using (var fileTest = System.IO.File.Open(#"c:\temp\fileNoCloseNoFlush.bin", FileMode.CreateNew))
{
fileTest.Write(randomBytes, 0, randomBytes.Length);
}
using (var fileTest = System.IO.File.Open(#"c:\temp\fileCloseNoFlush.bin", FileMode.CreateNew))
{
fileTest.Write(randomBytes, 0, randomBytes.Length);
fileTest.Close();
}
using (var fileTest = System.IO.File.Open(#"c:\temp\fileFlushNoClose.bin", FileMode.CreateNew))
{
fileTest.Write(randomBytes, 0, randomBytes.Length);
fileTest.Flush();
}
using (var fileTest = System.IO.File.Open(#"c:\temp\fileCloseAndFlush.bin", FileMode.CreateNew))
{
fileTest.Write(randomBytes, 0, randomBytes.Length);
fileTest.Flush();
fileTest.Close();
}
And again - every file got its bytes ... to me it looks like it's doing what I read from MSDN: it doesn't matter if you call Flush or Close before dispose ... any thoughts on that?
You don't have to call Flush() on Close()/Dispose(), FileStream will do it for you as you can see from its source code:
http://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs,e23a38af5d11ddd3
[System.Security.SecuritySafeCritical] // auto-generated
protected override void Dispose(bool disposing)
{
// Nothing will be done differently based on whether we are
// disposing vs. finalizing. This is taking advantage of the
// weak ordering between normal finalizable objects & critical
// finalizable objects, which I included in the SafeHandle
// design for FileStream, which would often "just work" when
// finalized.
try {
if (_handle != null && !_handle.IsClosed) {
// Flush data to disk iff we were writing. After
// thinking about this, we also don't need to flush
// our read position, regardless of whether the handle
// was exposed to the user. They probably would NOT
// want us to do this.
if (_writePos > 0) {
FlushWrite(!disposing); // <- Note this
}
}
}
finally {
if (_handle != null && !_handle.IsClosed)
_handle.Dispose();
_canRead = false;
_canWrite = false;
_canSeek = false;
// Don't set the buffer to null, to avoid a NullReferenceException
// when users have a race condition in their code (ie, they call
// Close when calling another method on Stream like Read).
//_buffer = null;
base.Dispose(disposing);
}
}
I've been tracking a newly introduced bug that seems to indicate .NET 4 does not reliably flush changes to disk when the stream is disposed (unlike .NET 2.0 and 3.5, which always did so reliably).
The .NET 4 FileStream class has been heavily modified in .NET 4, and while the Flush*() methods have been rewritten, similar attention seems to have been forgotten for .Dispose().
This is resulting in incomplete files.
Since you've stated that you understood that close & dispose called the flush method if it was not called explicitly by user code, I believe that (by close without flush) you actually want to have a possibility to discard changes made to a FileStream, if necessary.
If that is correct, using a FileStream alone won't help. You will need to load this file into a MemoryStream (or an array, depending on how you modify its contents), and then decide whether you want to save changes or not after you're done.
A problem with this is file size, obviously. FileStream uses limited size write buffers to speed up operations, but once they are depleted, changes need to be flushed. Due to .NET memory limits, you can only expect to load smaller files in memory, if you need to hold them entirely.
An easier alternative would be to make a disk copy of your file, and work on it using a plain FileStream. When finished, if you need to discard changes, simply delete the temporary file, otherwise replace the original with a modified copy.
Wrap the FileStream in a BufferedStream and close the filestream before the buffered stream.
var fs = new FileStream(...);
var bs = new BufferedStream(fs, buffersize);
bs.Write(datatosend, 0, length);
fs.Close();
try {
bs.Close();
}
catch (IOException) {
}
Using Flush() is worthy inside big Loops.
when you have to read and write a big File inside one Loop. In other case the buffer or the computer is big enough, and doesn´t matter to close() without making one Flush() before.
Example: YOU HAVE TO READ A BIG FILE (in one format) AND WRITE IT IN .txt
StreamWriter sw = .... // using StreamWriter
// you read the File ...
// and now you want to write each line for this big File using WriteLine ();
for ( .....) // this is a big Loop because the File is big and has many Lines
{
sw.WriteLine ( *whatever i read* ); //we write here somrewhere ex. one .txt anywhere
sw.Flush(); // each time the sw.flush() is called, the sw.WriteLine is executed
}
sw.Close();
Here it is very important to use Flush(); beacause otherwise each writeLine is save in the buffer and does not write it until the buffer is frull or until the program reaches sw.close();
I hope this helps a little to understand the function of Flush
I think it is safe to use simple using statement, which closes the stream after the call to GetBytes();
public static byte[] GetBytes(string fileName)
{
byte[] buffer = new byte[4096];
using (FileStream fs = new FileStream(fileName))
using (MemoryStream ms = new MemoryStream())
{
fs.BlockCopy(ms, buffer, 4096); // extension method for the Stream class
fs.Close();
return ms.ToByteArray();
}
}
Related
I was trying to compress a byte array using DeflateStream. After wring the data, I was looking for a way to close the compression (mark as done). At first, I tried Dispose() then Close(), but those made the result MemoryStream unreadable. Then I thought I may need to Flush(), but the description said "The current implementation of this method has no functionality"
But it seems that without Flush(), the result seems empty. What does it mean that "The current implementation of this method has no functionality"?
static void Main(string[] args)
{
byte[] result = Encoding.UTF8.GetBytes("わたしのこいはみなみのかぜにのってはしるわ");
var output = new MemoryStream();
var dstream = new DeflateStream(output, CompressionLevel.Optimal);
dstream.Write(result, 0, result.Length);
var compressedSize1 = output.Position;
dstream.Flush();
var compressedSize2 = output.Position;
What does it mean that "The current implementation of this method has no functionality" ?
it means: it doesn't do anything, so calling Flush() by itself isn't going to help. You need to close the deflate stream for it to finish writing what it needs, but without closing the underlying stream (blocks will be written as you write to the stream, as the internal buffer fills - but the final partial block cannot be written until the data is ready to be terminated; not all compression sequences support being able to flush at an arbitrary point and then resume compressed data in additional blocks)
What you probably want is:
using (var dstream = new DeflateStream(output, CompressionLevel.Optimal, true))
{
// Your deflate code
}
// Now check the memory stream
Note the extra bool leaveOpen parameter usage.
using (var stream = GetS3ObjectStream(fooObj))
{
WriteStreamToFtp(stream, "ftp://firstserver");
WriteStreamToFtp(stream, "ftp://SecondServer");
}
First one would work, but the second one will create just an empty file
GetS3ObjectStream gets a stream for Amazon Simple storage object. It's unseakable stream and you can't change the cursor position in it.
Now, I either have to somehow restrict to use the stream object more than once or I have to to move the cursor to the beginning.
any ideas?
upd: yeah of course you can simply save the stream in temp. variable, but if you don't wanna do that, what then? is it ok to make methods that take streams and leave them with such side-effects?
what if I close and dispose the source stream in the method?
You can either re-create your stream or buffer it into a byte[] or MemoryStream before use.
Edit: I forgot to mention a solution which does not buffer:
Open the two destination streams
Open the source stream
Until the source is drained, read a buffer of N bytes and write the buffer to both destination streams (you can even do the writing in parallel using Parallel.Invoke())
Here’s an example of how it may be done reading the stream just once (without initializing a temporary copy of the stream’s contents).
This assumes that you can replace your WriteStreamToFtp call with access to the actual target stream. Note that the FtpStream constructor is placeholder code.
using (var source = GetS3ObjectStream(fooObj))
using (var target1 = new FtpStream("ftp://firstserver"))
using (var target2 = new FtpStream("ftp://SecondServer"))
{
byte[] buffer = new byte[1024];
while (true)
{
int count = source.Read(buffer, 0, buffer.Length);
if (count == 0)
break;
target1.Write(buffer, 0, count);
target2.Write(buffer, 0, count);
}
}
I'm writing code that deals with a file that uses hashes. I need to read a chunk, then hash it, then write it, then read another chunk, etc.
In other words, I need to do a lot of reading and writing. I'm sure this is really simple, but I just wanted to run it by the pros...
Is it possible, and acceptable to do something like:
BinaryReader br = new BinaryReader (File.OpenRead(path));
BinaryWriter bw = new BinaryWriter (File.OpenWrite(path));
br.dostuff();
bw.dostuff();
I remember running into some sort of conflicting file streams error when experimenting with opening and writing to files, and I'm not sure what I had done to get it. Is it two file streams that's the issue? Can I have one stream to read from and write to?
This is perfecty possible and desired, A technicality, if your write method doesn't change the length of the file and is always behind the reader, this should not give any problems. In fact, from an API point of view, this is desirable since this allows the user to control where to read from and where to write to. (It's a recommended specification to write to a different file, in case any bad things happen during the encryption process, your input file wont be messed up).
Something like:
protected void Encrypt(Stream input, Stream output)
{
byte[] buffer = new byte[2048];
while (true)
{
// read
int current = input.Read(buffer, 0, buffer.Length);
if (current == 0)
break;
// encrypt
PerformActualEncryption(buffer, 0, current);
// write
output.Write(buffer, 0, current);
}
}
public void Main()
{
using (Stream inputStream = File.Open("file.dat", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (Stream outputStream = File.Open("file.dat", FileMode.Open, FileAccess.Write, FileShare.ReadWrite))
{
Encrypt(inputStream, outputStream);
}
}
Now since you're using an encryption, i would even recommend to perform the actual encryption in another specialized stream. This cleans the code up nicely.
class MySpecialHashingStream : Stream
{
...
}
protected void Encrypt(Stream input, Stream output)
{
Stream encryptedOutput = new MySpecialHashingStream(output);
input.CopyTo(encryptedOutput);
}
When I run code analysis on the following chunk of code I get this message:
Object 'stream' can be disposed more than once in method 'upload.Page_Load(object, EventArgs)'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.
using(var stream = File.Open(newFilename, FileMode.CreateNew))
using(var reader = new BinaryReader(file.InputStream))
using(var writer = new BinaryWriter(stream))
{
var chunk = new byte[ChunkSize];
Int32 count;
while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
{
writer.Write(chunk, 0, count);
}
}
I don't understand why it might be called twice, and how to fix it to eliminate the error. Any help?
I struggled with this problem and found the example here to be very helpful. I'll post the code for a quick view:
using (Stream stream = new FileStream("file.txt", FileMode.OpenOrCreate))
{
using (StreamWriter writer = new StreamWriter(stream))
{
// Use the writer object...
}
}
Replace the outer using statement with a try/finally making sure to BOTH null the stream after using it in StreamWriter AND check to make sure it is not null in the finally before disposing.
Stream stream = null;
try
{
stream = new FileStream("file.txt", FileMode.OpenOrCreate);
using (StreamWriter writer = new StreamWriter(stream))
{
stream = null;
// Use the writer object...
}
}
finally
{
if(stream != null)
stream.Dispose();
}
Doing this cleared up my errors.
To illustrate, let's edit your code
using(var stream = File.Open(newFilename, FileMode.CreateNew))
{
using(var reader = new BinaryReader(file.InputStream))
{
using(var writer = new BinaryWriter(stream))
{
var chunk = new byte[ChunkSize];
Int32 count;
while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
{
writer.Write(chunk, 0, count);
}
} // here we dispose of writer, which disposes of stream
} // here we dispose of reader
} // here we dispose a stream, which was already disposed of by writer
To avoid this, just create the writer directly
using(var reader = new BinaryReader(file.InputStream))
{
using(var writer = new BinaryWriter( File.Open(newFilename, FileMode.CreateNew)))
{
var chunk = new byte[ChunkSize];
Int32 count;
while((count = reader.Read(chunk, 0, ChunkSize)) > 0)
{
writer.Write(chunk, 0, count);
}
} // here we dispose of writer, which disposes of its inner stream
} // here we dispose of reader
edit: to take into account what Eric Lippert is saying, there could indeed be a moment when the stream is only released by the finalizer if BinaryWriter throws an exception. According to the BinaryWriter code, that could occur in three cases
If (output Is Nothing) Then
Throw New ArgumentNullException("output")
End If
If (encoding Is Nothing) Then
Throw New ArgumentNullException("encoding")
End If
If Not output.CanWrite Then
Throw New ArgumentException(Environment.GetResourceString("Argument_StreamNotWritable"))
End If
if you didn't specify an output, ie if stream is null. That shouldn't be a problem since a null stream means no resources to dispose of :)
if you didn't specify an encoding. since we don't use the constructor form where the encoding is specified, there should be no problem here either (i didn't look into the encoding contructor too much, but an invalid codepage can throw)
if you don't pass a writable stream. That should be caught quite quickly during development...
Anyway, good point, hence the edit :)
The BinaryReader/BinaryWriter will dispose the underlying stream for you when it disposes. You don't need to do it explicitly.
To fix it you can remove the using around the Stream itself.
A proper implementation of Dispose is explicitly required not to care if it's been called more than once on the same object. While multiple calls to Dispose are sometimes indicative of logic problems or code which could be better written, the only way I would improve the original posted code would be to convince Microsoft to add an option to BinaryReader and BinaryWriter instructing them not to dispose their passed-in stream (and then use that option). Otherwise, the code required to ensure the file gets closed even if the reader or writer throws in its constructor would be sufficiently ugly that simply letting the file get disposed more than once would seem cleaner.
Your writer will dispose your stream, always.
Suppress CA2202 whenever you are sure that the object in question handles multiple Dispose calls correctly and that your control flow is impeccably readable. BCL objects generally implement Dispose correctly. Streams are famous for that.
But don't necessarily trust third party or your own streams if you don't have unit tests probing that scenario yet. An API which returns a Stream may be returning a fragile subclass.
What is the best method to convert a Stream to a FileStream using C#.
The function I am working on has a Stream passed to it containing uploaded data, and I need to be able to perform stream.Read(), stream.Seek() methods which are methods of the FileStream type.
A simple cast does not work, so I'm asking here for help.
Read and Seek are methods on the Stream type, not just FileStream. It's just that not every stream supports them. (Personally I prefer using the Position property over calling Seek, but they boil down to the same thing.)
If you would prefer having the data in memory over dumping it to a file, why not just read it all into a MemoryStream? That supports seeking. For example:
public static MemoryStream CopyToMemory(Stream input)
{
// It won't matter if we throw an exception during this method;
// we don't *really* need to dispose of the MemoryStream, and the
// caller should dispose of the input stream
MemoryStream ret = new MemoryStream();
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
{
ret.Write(buffer, 0, bytesRead);
}
// Rewind ready for reading (typical scenario)
ret.Position = 0;
return ret;
}
Use:
using (Stream input = ...)
{
using (Stream memory = CopyToMemory(input))
{
// Seek around in memory to your heart's content
}
}
This is similar to using the Stream.CopyTo method introduced in .NET 4.
If you actually want to write to the file system, you could do something similar that first writes to the file then rewinds the stream... but then you'll need to take care of deleting it afterwards, to avoid littering your disk with files.