В приведенном ниже примере программы метод ReadByte используется для ввода и отображения содержимого текстового файла, имя которого указывается в ка честве аргумента командной строки. Обратите внимание на то, что в этой программе проверяется, указано ли имя файла, прежде чем пытаться открыть его. /* Отобразить содержимое текстового файла. Чтобы воспользоваться этой программой, укажите имя того файла, содержимое которого требуется отобразить. Например, для просмотра содержимого файла TEST.CS введите в командной строке следующее: ShowFile TEST.CS */ using System; using System.IO; class ShowFile { static void Main(string[] args) { int i; FileStream fin; if(args.Length != 1) { Console.WriteLine("Применение: ShowFile Файл"); return; } try { fin = new FileStream(args[0], FileMode.Open); } catch(IOException exc) { Console.WriteLine("He удается открыть файл"); Console.WriteLine(exc.Message); return; // Файл не открывается, завершить программу } // Читать байты до конца файла. try { do { i = fin.ReadByte; if(i != -1) Console.Write((char) i); } while(i != -1); } catch(IOException exc) { Console.WriteLine("Ошибка чтения файла"); Console.WriteLine(exc.Message); } finally { fin.Close; } } }
Обратите внимание на то, что в приведенной выше программе применяются два блока try. В первом из них перехватываются исключения, возникающие при вводе- выводе и способные воспрепятствовать открытию файла. Если произойдет ошибка ввода-вывода, выполнение программы завершится. В противном случае во втором блоке try будет продолжен контроль исключений, возникающих в операциях ввода- вывода. Следовательно, второй блок try выполняется только в том случае, если в пере менной fin содержится ссылка на открытый файл. Обратите также внимание на то, что файл закрывается в блоке finally, связанном со вторым блоком try. Это означа ет, что независимо от того, как завершится цикл do-while (нормально или аварийно из-за ошибки), файл все равно будет закрыт. И хотя в данном конкретном примере это и так важно, поскольку программа все равно завершится в данной точке, преиму щество такого подхода, вообще говоря, заключается в том, что файл закрывается в за вершающем блоке finally в любом случае — даже если выполнение кода доступа к этому файлу завершается преждевременно из-за какого-нибудь исключения.
В некоторых случаях оказывается проще заключить те части программы, где осу ществляется открытие и доступ к файлу, внутрь блока try, вместо того чтобы разделять обе эти операции. В качестве примера ниже приведен другой, более краткий вариант написания представленной выше программы ShowFile. // Отобразить содержимое текстового файла. using System; using System.IO; class ShowFile { static void Main(string[] args) { int i; FileStream fin = null; if(args.Length != 1) { Console.WriteLine("Применение: ShowFile File"); return; } // Использовать один блок try для открытия файла и чтения из него try { fin = new FileStream(args[0], FileMode.Open); // Читать байты до конца файла. do { i = fin.ReadByte; if(i != -1) Console.Write((char) i); } while(i != -1); } catch(IOException exc) { Console.WriteLine("Ошибка ввода-вывода:\n" + exc.Message); } finally { if(fin != null) fin.Close; } } }
Обратите внимание на то, что в данном варианте программы переменная fin ссылки на объект класса FileStream инициализируется пустым значением. Если файл удастся открыть в конструкторе класса FileStream, то значение переменной fin окажется непустым, а иначе — оно так и останется пустым. Это очень важно, по скольку метод Close вызывается внутри блока finally только в том случае, если значение переменной fin оказывается непустым. Подобный механизм препятствует любой попытке вызвать метод Close для переменной fin, когда она не ссылается на открытый файл. Благодаря своей компактности такой подход часто применяется во многих примерах организации ввода-вывода, приведенных далее в этой книге. Сле дует, однако, иметь в виду, что он не пригоден в тех случаях, когда ситуацию, возни кающую в связи с невозможностью открыть файл, нужно обрабатывать отдельно. Так, если пользователь неправильно введет имя файла, то на экран, возможно, придется вывести приглашение правильно ввести имя файла, прежде чем входить в блок try, где осуществляется проверка правильности доступа к файлу.