Закройте файловый поток без Flush () - PullRequest
23 голосов
/ 11 сентября 2011

Могу ли я закрыть поток файлов, не вызывая Flush (в C #)? Я понял, что Close и Dispose сначала вызывают метод Flush.

Ответы [ 7 ]

16 голосов
/ 11 сентября 2011

MSDN не очищен на 100%, но Джон Скит говорит «Флеш», так что сделайте это, прежде чем закрыть / утилизировать.Это не повредит, верно?

С Метод FileStream.Close :

Все данные, ранее записанные в буфер, копируютсяк файлу до закрытия файлового потока, поэтому нет необходимости вызывать Flush перед вызовом Close.После вызова Close любые операции с файловым потоком могут вызывать исключения.После того, как Close был вызван один раз, он ничего не делает, если вызывается снова.

Утилизация не так ясна:

Этот метод удаляет поток, записывая любые изменения всохранение хранилища и закрытие потока для освобождения ресурсов.

Примечание: комментаторы могут быть правы, это не на 100% ясно из Flush:

Переопределить 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, прежде чем утилизировать ... какие-либо мысли по этому поводу?

12 голосов
/ 18 февраля 2015

У вас нет для вызова Flush() на Close()/Dispose(), 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);
        }
    }
4 голосов
/ 06 августа 2013

Я отслеживал недавно появившуюся ошибку, которая, кажется, указывает, что .NET 4 не надежно сбрасывает изменения на диск при удалении потока (в отличие от .NET 2.0 и 3.5, которые всегда делали это надежно).

Класс .NET 4 FileStream был сильно изменен в .NET 4, и хотя методы Flush * () были переписаны, подобное внимание, похоже, было забыто для .Dispose ().

Это приводит к неполным файлам.

3 голосов
/ 11 сентября 2011

Поскольку вы заявили, что поняли, что close & dispose называется методом сброса , если он не был вызван явно кодом пользователя, я считаю, что (при закрытии без сброса) вы действительно хотите иметь возможность отменить изменения, внесенные в FileStream, если необходимо.

Если это правильно, использование только FileStream не поможет. Вам нужно будет загрузить этот файл в MemoryStream (или массив, в зависимости от того, как вы измените его содержимое), а затем решить, хотите ли вы сохранить изменения или нет после того, как вы закончите.

Проблема в этом, очевидно, в размере файла. FileStream использует буферы записи ограниченного размера для ускорения операций, но как только они исчерпаны, изменения должны быть сброшены. Из-за ограничений памяти .NET вы можете ожидать загрузки файлов меньшего размера только в том случае, если вам нужно хранить их полностью.

Более простой альтернативой было бы сделать диск копии вашего файла и работать с ним, используя простой FileStream. По завершении, если вам нужно отменить изменения, просто удалите временный файл, в противном случае замените оригинал измененной копией.

0 голосов
/ 19 марта 2014

Использование Flush () достойно больших циклов. когда вам нужно прочитать и написать большой файл внутри одного цикла. В другом случае буфер или компьютер достаточно велики, и не важно закрывать (), не сделав один Flush () раньше.

Пример: ВЫ ДОЛЖНЫ ПРОЧИТАТЬ БОЛЬШОЙ ФАЙЛ (в одном формате) И НАПИШИТЕ ЭТО В .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

0 голосов
/ 12 сентября 2011

Я думаю, что безопасно использовать простой с использованием оператора , который закрывает поток после вызова 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();
    }
}
0 голосов
/ 11 сентября 2011

Оберните FileStream в BufferedStream и закройте поток файлов перед буферизованным потоком.

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

bs.Write(datatosend, 0, length);

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