Подтвердить что ты не робот

Закрыть поток без Flush()

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

4b9b3361

Ответ 1

MSDN не на 100% понятен, но Джон Скит говорит "Flush", поэтому делайте это до закрытия/удаления. Это не повредит, правильно?

Из FileStream.Close Method:

Любые данные, ранее записанные в буфер, копируются в файл до поток файлов закрыт, поэтому нет необходимости вызывать 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 перед тем, как распоряжаться... какие-нибудь мысли по этому поводу?

Ответ 2

Вам не нужно вызывать 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);
        }
    }

Ответ 3

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

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

bs.Write(datatosend, 0, length);

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

Ответ 6

Использование 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(); beakause иначе каждая writeLine сохраняется в буфере и не записывает ее до тех пор, пока буфер не станет пустым или пока программа не достигнет sw.close();

Надеюсь, это поможет немного понять функцию Flush

Ответ 7

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