Можно ли закрыть поток файлов без вызова Flush
(на С#)? Я понял, что Close
и Dispose
сначала вызывает метод Flush
.
Закрыть поток без Flush()
Ответ 1
MSDN не на 100% понятен, но Джон Скит говорит "Flush", поэтому делайте это до закрытия/удаления. Это не повредит, правильно?
Любые данные, ранее записанные в буфер, копируются в файл до поток файлов закрыт, поэтому нет необходимости вызывать 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();
}
}