В чем разница между закрытием FileStream и присвоением ему значения null?

#c#-3.0

#c #-3.0

Вопрос:

У меня есть следующий код для чтения и записи одной строки в текстовый файл. Можем ли мы присвоить null объектам reader и writer в конце обработки? или я должен вызвать метод Close ()? Спасибо.

 FileInfo JFile = new FileInfo(@"C:test.txt");
            using (FileStream JStream = JFile.Open(FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
            {
                StreamReader reader = null;
                StreamWriter writer = null;
                try
                {
                    int n;
                    reader = new StreamReader(JStream);
                    string line = reader.ReadLine();
                    int.TryParse(line, out n);

                    n = n   1;

                    writer = new StreamWriter(JStream);
                    JStream.Seek(0, SeekOrigin.Begin);
                    writer.WriteLine(n);
                    writer.Flush();
                }
                catch (Exception x)
                {
                    string message = string.Format("Error while processing the file. {0}", x.Message);
                    System.Windows.Forms.MessageBox.Show(message);
                }

                reader = null;
                writer = null;
            }
  

Комментарии:

1. Спасибо всем за замечательные объяснения. Я использую один и тот же объект FileStream для создания StreamReader и StreamWriter. Если я вызываю метод Close () как для объектов reader, так и для объектов writer, я получаю сообщение об ошибке «Не удается получить доступ к закрытому файлу», когда оно достигает writer. Закрыть(). Я думаю, потому что reader. Close() уже закрывает поток чтения и базовый поток файлов. Я не могу создавать разные потоки для reader и writer, так как мне приходится блокировать файл до тех пор, пока он не завершит запись в file.

2. есть идеи, что делать в этом случае? Спасибо.

Ответ №1:

При закрытии файла должны произойти определенные вещи. Например, когда ваша программа обращается к файлу и создает для него дескриптор. .Close() -редактирование потока позволяет платформе немедленно освободить дескриптор и другие подобные ресурсы.

Когда вы устанавливаете для него значение null , вы полагаетесь на сборщик мусора, который выполняет эту важную функциональность за вас. GC может очистить все это сейчас, а может и нет. Вы не знаете, когда это произойдет. Если ваша программа выйдет из строя, она может вообще никогда не освободить дескриптор.

Всегда полезно .Close() запустить поток самостоятельно, как только вы закончите.

Комментарии:

1. Отличное объяснение того, что происходит.

Ответ №2:

Вы должны вызывать метод Close, чтобы освободить все базовые неуправляемые ресурсы. Присвоение объекту значения null не освобождает ресурсы. Подробности см. http://msdn.microsoft.com/en-us/library/system.io.stream.close.aspx

Обновление: Поскольку ваш код находится внутри инструкции using, метод Dispose будет автоматически вызван после завершения выполнения внутри инструкции using .

Ответ №3:

Когда вы присваиваете объекту значение null, вы сообщаете среде CLR, что он вам больше не нужен и запланирован для сборки мусора. Проблема, с которой вы столкнетесь, заключается в том, что перехваты среды CLR в файл, который вы открыли, не освобождаются до тех пор, пока ваша программа не завершится и среда CLR не будет закрыта. Когда вы вызываете метод Close(), файловые ресурсы очищаются, а затем все фрагменты должным образом планируются для сборки мусора.

если вы откроете streamreader в блоке using, он позаботится и об этом за вас, но вы потеряете часть мелкозернистой обработки ошибок, которую вы получаете с помощью блока try / catch / finally.

Ответ №4:

Как StreamReader , так и StreamWriter implementate IDisposable , что является их способом сказать

«Когда вы закончите со мной, пожалуйста, вызовите этот метод ( Dispose() ), чтобы я знал, что вы закончили со мной, и я мог привести себя в порядок».

(Это также называется детерминированным завершением)

Итак, вам нужно вызвать Dispose для них или обернуть их в using инструкцию, которая просто делает то же самое для вас. В случае этих двух классов Dispose будет выполнен внутренний вызов Close , если он еще не закрыт.

Ответ №5:

На самом деле вы хотите вызвать Close() или, еще лучше, Dispose(), чтобы убедиться, что все содержимое удалено. Вы рискуете не записать буфер, если явно не закроете / не утилизируете средство записи.

Ответ №6:

Я думаю, лучшим решением будет использовать using statment (как вы сделали в FileStream ). Он позаботится обо всей очистке.