不使用 Flush() 关闭文件流

发布于 2024-12-04 03:38:55 字数 421 浏览 1 评论 0原文

我可以在不调用 刷新(在C#中)?我了解 关闭处置首先调用Flush方法。

Can I close a file stream without calling Flush (in C#)? I understood that Close and Dispose calls the Flush method first.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

把回忆走一遍 2024-12-11 03:38:55

不必Close()/Dispose() 上调用 Flush()FileStream 即可正如您可以从其源代码中看到的那样:

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);
        }
    }

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);
        }
    }
も让我眼熟你 2024-12-11 03:38:55

MSDN 不是 100% 清楚,但 Jon Skeet 说的是“Flush”,所以在关闭/处置之前执行此操作。不会痛的,对吧?

来自FileStream.Close 方法

之前写入缓冲区的任何数据都会在之前复制到文件中
文件流已经关闭,所以之前不需要调用Flush
调用关闭。调用 Close 之后,对文件的任何操作
流可能会引发异常。 Close 被调用一次后,
如果再次调用,则不会执行任何操作。

处置不太清楚:

此方法通过将任何更改写入支持来处理流
存储并关闭流以释放资源。

备注:评论者可能是对的,从同花顺中并不是 100% 清楚:

重写实现缓冲区的流上的 Flush。使用此方法可以
将任何信息从底层缓冲区移动到其目的地,
清除缓冲区,或两者都清除。根据对象的状态,您
可能必须修改流中的当前位置(例如
例如,如果底层流支持查找)。对于额外的
信息请参阅 CanSeek。

使用 StreamWriter 或 BinaryWriter 类时,不要刷新
基本 Stream 对象。相反,使用类的 Flush 或 Close 方法,
这确保数据被刷新到底层流
首先,然后写入文件。

测试:

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();
}

我能说什么......所有文件都有文本 - 也许这只是数据太少了?

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();
}

再说一遍 - 每个文件都有它的字节......对我来说,它看起来就像我从 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:

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?

慈悲佛祖 2024-12-11 03:38:55

既然您已经说过您理解了 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 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.

好听的两个字的网名 2024-12-11 03:38:55

我一直在跟踪一个新引入的错误,该错误似乎表明 .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.

苏大泽ㄣ 2024-12-11 03:38:55

FileStream 包装在 BufferedStream 中,并在缓冲流之前关闭文件流。

var fs = new FileStream(...);
var bs = new BufferedStream(fs, buffersize);

bs.Write(datatosend, 0, length);

fs.Close();
try {
    bs.Close();
}
catch (IOException) {
}

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) {
}
醉态萌生 2024-12-11 03:38:55

在大循环中使用 Flush() 是值得的。
当您必须在一个循环内读取和写入一个大文件时。在其他情况下,缓冲区或计算机足够大,并且在之前不进行 Flush() 操作的情况下 close() 并不重要。

示例:您必须读取一个大文件(以一种格式)并将其写入 .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();

这里使用 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

 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

栖迟 2024-12-11 03:38:55

我认为使用简单的 using 语句是安全的,该语句在调用 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();
    }
}

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();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文