[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);
}
}
You don't have to call Flush() on Close()/Dispose(), FileStream will do it for you as you can see from its source code:
[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);
}
}
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?
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.
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().
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();
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
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();
}
}
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();
}
}
发布评论
评论(7)
您不必在
Close()/Dispose()
上调用Flush()
,FileStream
即可正如您可以从其源代码中看到的那样:http://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs,e23a38af5d11ddd3
You don't have to call
Flush()
onClose()/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
MSDN 不是 100% 清楚,但 Jon Skeet 说的是“Flush”,所以在关闭/处置之前执行此操作。不会痛的,对吧?
来自FileStream.Close 方法 :
处置不太清楚:
备注:评论者可能是对的,从同花顺中并不是 100% 清楚:
测试:
我能说什么......所有文件都有文本 - 也许这只是数据太少了?
Test2
再说一遍 - 每个文件都有它的字节......对我来说,它看起来就像我从 MSDN 上读到的那样:如果你在处理之前调用 Flush 或 Close 并不重要......对此有什么想法吗?
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:
Dispose is not as clear:
Remark: the commentators might be right, it's not 100% clear from the Flush:
TESTS:
What can I say ... all files got the text - maybe this is just too little data?
Test2
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?
既然您已经说过您理解了 close &如果用户代码没有显式调用,则 dispose 调用了刷新方法,我相信(通过关闭而不刷新)您实际上希望有可能放弃对
所做的更改>FileStream
,如果需要的话。如果这是正确的,那么单独使用
FileStream
是没有帮助的。您需要将此文件加载到 MemoryStream(或数组,具体取决于您修改其内容的方式),然后决定完成后是否要保存更改。显然,这样做的一个问题是文件大小。 FileStream 使用有限大小的写入缓冲区来加速操作,但是一旦它们耗尽,就需要刷新更改。由于 .NET 内存限制,如果您需要完全保存较小的文件,则只能将其加载到内存中。
一个更简单的替代方案是制作文件的磁盘副本,并使用普通的
FileStream
对其进行处理。完成后,如果您需要放弃更改,只需删除临时文件,否则用修改后的副本替换原始文件。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 aMemoryStream
(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.我一直在跟踪一个新引入的错误,该错误似乎表明 .NET 4 在处理流时无法可靠地将更改刷新到磁盘(与 .NET 2.0 和 3.5 不同,它们总是如此可靠)。
.NET 4 FileStream 类在 .NET 4 中进行了大量修改,虽然 Flush*() 方法已被重写,但 .Dispose() 似乎已经忘记了类似的注意。
这会导致文件不完整。
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.
将
FileStream
包装在BufferedStream
中,并在缓冲流之前关闭文件流。Wrap the
FileStream
in aBufferedStream
and close the filestream before the buffered stream.在大循环中使用 Flush() 是值得的。
当您必须在一个循环内读取和写入一个大文件时。在其他情况下,缓冲区或计算机足够大,并且在之前不进行 Flush() 操作的情况下 close() 并不重要。
示例:您必须读取一个大文件(以一种格式)并将其写入 .txt
这里使用 Flush() 非常重要;因为否则每个 writeLine 都会保存在缓冲区中,并且直到缓冲区满或程序到达 sw.close() 时才会写入它;
希望对大家理解Flush的功能有一点帮助
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
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
我认为使用简单的 using 语句是安全的,该语句在调用 GetBytes() 后关闭流;
I think it is safe to use simple using statement, which closes the stream after the call to GetBytes();