简体   繁体   English

关闭没有Flush()的文件流

[英]Close a filestream without Flush()

Can I close a file stream without calling Flush (in C#)? 我可以在不调用Flush情况下关闭文件流(在C#中)吗? I understood that Close and Dispose calls the Flush method first. 我知道CloseDispose调用Flush方法。

MSDN is not 100% clear, but Jon Skeet is saying "Flush", so do it before close/dispose. MSDN并非100%明确,但Jon Skeet正在说“Flush”,所以在关闭/处置之前这样做。 It won't hurt, right? 它不会伤害,对吗?

From FileStream.Close Method : FileStream.Close方法

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. 先前写入缓冲区的任何数据都会在文件流关闭之前复制到文件中,因此在调用Close之前不必调用Flush。 Following a call to Close, any operations on the file stream might raise exceptions. 在调用Close之后,对文件流的任何操作都可能引发异常。 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: 备注:评论员可能是对的,它不是100%清除Flush:

Override Flush on streams that implement a buffer. 覆盖实现缓冲区的流上的Flush。 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. 有关其他信息,请参阅CanSeek。

When using the StreamWriter or BinaryWriter class, do not flush the base Stream object. 使用StreamWriter或BinaryWriter类时,请不要刷新基本Stream对象。 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. 相反,使用类的Flush或Close方法,该方法确保首先将数据刷新到基础流,然后写入文件。

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 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? 再一次 - 每个文件都得到了它的字节......对我来说,它看起来像是在做我从MSDN上读到的内容:如果你在处理之前调用Flush或Close也没关系......对此有什么看法?

You don't have to call Flush() on Close()/Dispose() , FileStream will do it for you as you can see from its source code : 不必Close()/Dispose() Flush()上调用Flush()FileStream将为您执行此操作,您可以从其源代码中看到:

http://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs,e23a38af5d11ddd3 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). 我一直在跟踪一个新引入的错误,似乎表明.NET 4在流处理时不能可靠地刷新磁盘更改(与.NET 2.0和3.5不同,它总是可靠地执行)。

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(). .NET 4 FileStream类在.NET 4中经过了大量修改,虽然Flush *()方法已被重写,但类似的注意力似乎已被忘记.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. 既然你已经说过你理解了关闭&dispose,如果它没有被用户代码明确调用,我认为(通过close而不刷新)你实际上想要放弃FileStream所做的更改,如有必要。

If that is correct, using a FileStream alone won't help. 如果这是正确的,单独使用FileStream将无济于事。 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. 您需要将此文件加载到MemoryStream (或数组中,具体取决于您修改其内容的方式),然后在完成后决定是否要保存更改。

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. FileStream使用有限大小的写缓冲区来加速操作,但一旦耗尽,就需要刷新更改。 Due to .NET memory limits, you can only expect to load smaller files in memory, if you need to hold them entirely. 由于.NET内存限制,您只能在内存中加载较小的文件,如果您需要完全保留它们。

An easier alternative would be to make a disk copy of your file, and work on it using a plain FileStream . 更简单的替代方法是制作文件的磁盘副本 ,并使用普通的FileStream处理它。 When finished, if you need to discard changes, simply delete the temporary file, otherwise replace the original with a modified copy. 完成后,如果您需要放弃更改,只需删除临时文件,否则将原始文件替换为修改后的副本。

Using Flush() is worthy inside big Loops. 使用Flush()在大循环中是值得的。 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. 在其他情况下,缓冲区或计算机足够大,并且在没有制作一个Flush()之前关闭()并不重要。

Example: YOU HAVE TO READ A BIG FILE (in one format) AND WRITE IT IN .txt 示例:您必须阅读大文件(以一种格式)并在.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(); 这里使用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(); 因为否则每个writeLine都保存在缓冲区中,并且在缓冲区为frull或程序到达sw.close()之前不会写入它。

I hope this helps a little to understand the function of Flush 我希望这有助于理解Flush的功能

Wrap the FileStream in a BufferedStream and close the filestream before the buffered stream. FileStream包装在BufferedStream并在缓冲流之前关闭文件流。

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

bs.Write(datatosend, 0, length);

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

I think it is safe to use simple using statement, which closes the stream after the call to GetBytes() ; 我认为使用简单的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();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM