Java: руководство для начинающих
Шрифт:
Для того чтобы создать байтовый поток и связать его с файлом, следует воспользоваться классом FilelnputStream или FileOutputStream. А для открытия файла достаточно создать объект одного из этих классов, передав имя файла конструктору в качестве параметра. В открытый файл можно записывать данные или читать их из него. Ввод данных из файла
Файл открывается для ввода созданием объекта типа FilelnputStream. Для этой цели чаще всего используется приведенная ниже форма объявления конструктора данного класса. FilelnputStream(String имя_файла) throws FileNotFoundException
В качестве параметра этому конструктору передается имя_файла, который требуется открыть. Если указанный файл не существует, генерируется исключениеFileNotFoundException.
Для чтения данных из файла служит метод read . Ниже приведена форма объявления этого метода, которой мы будем пользоваться в дальнейшем, int read throws IOException
При каждом вызове метод read
Завершив операции с файлом, следует закрыть его с помощью метода close , общая форма объявления которого выглядит следующим образом: void close throws IOException
При закрытии файла освобождаются связанные с ним системные ресурсы, чтобы использовать их для работы с другим файлом. Если же файл не будет закрыт, могут произойти “утечки памяти” из-за того, что часть памяти остается выделенной для неиспользуемых ресурсов. Ниже приведен пример программы, где метод read используется для ввода содержимого текстового файла. Имя файла задается с помощью параметра в командной строке при запуске программы на выполнение. Полученные данные выводятся на экран. Обратите внимание на то, что ошибки ввода-вывода обрабатываются с помощью блока try/catch. /* Отображение текстового файла. При вызове этой программы следует указать имя файла, содержимое которого требуется просмотреть. Например, для вывода на экран содержимого файла TEST.TXT, в командной строке нужно указать следующее: java ShowFile TEST.TXT */ import java.io.*; class ShowFile { public static void main(String args[]) { int i; FilelnputStream fin; // Прежде всего следует убедиться, что файл был указан, if(args.length != 1) { System.out.println("Usage: ShowFile File"); return; } try { // Открытие файла. fin = new FilelnputStream(args[0]); } catch(FileNotFoundException exc) { System.out.println("File Not Found"); return; } try { // читать из файла до тех пор, пока не встретится знак EOF. do { // Чтение из файла. i = fin.read; if(i != -1) System.out.print((char) i) ; // Если значение переменной i равно -1,значит, // достингут конец файла. } while (i != -1); } catch(IOException exc) { System.out.println("Error reading file."); } try { // Закрытие файла. fin.close ; } catch(IOException exc) { System.out.println("Error closing file."); } } }
В приведенном выше примере поток ввода из файла закрывается после того, как чтение данных из файла завершается в блоке try. Такой способ оказывается удобным не всегда, и поэтому в Java предоставляется более совершенный и чаще употребляемый способ. А состоит он в вызове метода close в блоке finally. В этом случае все методы, получающие доступ к файлу, помещаются в блок try, а для закрытия файла используется блок finally. Благодаря этому файл закрывается независимого от того, как завершится блок try. Если продолжить предыдущий пример, то блок try, в котором выполняется чтение из файла, можно переписать следующим образом: try { do { i = fin.read; if(i != -1) System.out.print((char) i) ; } while(i != —1) ; } catch(IOException exc) { System.out.println("Error Reading File"); // Блок finally используется для закрытия файла. } finally { // закрыть файл при выходе из блока try. try { fin.close ; } catch(IOException exc) { System.out.println("Error Closing File"); } }
Преимущество рассмотренного выше способа состоит, в частности, в том, что если программа, получающая доступ к файлу, завершается аварийно из-за какой-нибудь ошибки ввода-вывода, генерирующей исключение, файл все равно закрывается в блоке finally. И если с аварийным завершением простых программ, как в большинстве примеров в этой книге, из-за неожиданно возникающей исключительной ситуации еще можно как-то мириться, то в крупных программах подобная ситуация вряд ли вообще допустима. Именно ее и позволяет исключить блок finally.
Иногда оказывается проще заключить в оболочку те части программы, в которых открывается файл, чтобы получить доступ к нему из единственного блока try, не разделяя его на два блока, а для закрытия файла использовать отдельный блок finally. В качестве примера ниже приведена переделанная версия рассмотренной выше программы ShowFile. /* В этой версии программы отображения текстового файла код, открывающий файл и получающий к нему доступ, заключается в единственный блок try. А закрывается файл в блоке finally. */ import java.io.*; class ShowFile { public static void main(String args[]) { int i; FilelnputStream fin = null; // Прежде всего следует убедиться, что файл был указан, if (args.length != 1) { System.out.println("Usage: ShowFile filename"); return; } // В следующем коде открывается файл, из которого читаются // символы до тех пор, пока не встретится знак EOF, а затем // файл закрывается в блоке finally, try { fin = new FilelnputStream(args[0]); do { i = fin.read ; if(i != -1) System.out.print((char) i); } while(i != -1); } catch(FileNotFoundException exc) { System.out.println("File Not Found."); } catch(IOException exc) { System.out.println("An I/O Error Occurred"); } finally { //
Обратите внимание на то, что переменная fin инициализируется пустым значением null. А в блоке finally файл закрывается только в том случае, если значение переменной fin не является пустым. Такой способ оказывается вполне работоспособным, поскольку переменная fin не будет содержать пустое значение лишь в том случае, если файл был успешно открыт. Следовательно, метод close не будет вызываться, если во время открытия файла возникнет исключение.
В приведенном выше примере блок try/catch можно сделать более компактным. Ведь исключение FileNotFoundException является подклассом исключения IOException, и поэтому его не нужно перехватывать отдельно. В качестве примера ниже приведен блок оператора catch, которым можно воспользоваться для перехвата обоих этих исключений, не прибегая к перехвату исключения FileNotFoundException в отдельности. В данном случае выводится стандартное сообщение о возникшем исключении с описанием характера ошибки. } catch(IOException exc) { System.out.println("I/O Error: " + exc); } finally { ... В рассматриваемом здесь способе любая ошибка, в том числе и ошибка открытия файла, будет обработана единственным оператором catch. Благодаря своей компактности именно такой способ применяется в большинстве примеров ввода-вывода, представленных в этой книге. Следует, однако, иметь в виду, что он может оказаться не вполне пригодным в тех случаях, когда требуется отдельно обрабатывать ошибку открытия файла, например, вследствие того, что пользователь введет имя файла с опечаткой. В подобных случаях рекомендуется выдать сначала приглашение правильно ввести имя файла, а затем перейти к блоку try для доступа к файлу. ### Вывод в файл Для того чтобы открыть файл для вывода, следует создать объект типа FileOutputStream. Ниже приведены два наиболее часто употребляемых конструктора этого класса.
FileOutputStream(String имяфайла) throws FileNotFoundException FileOutputStream(String имяфайлаг boolean append) throws FileNotFoundException Если файл не может быть создан, возникает исключение FileNotFoundException. В первой форме конструктора при открытии файла удаляется существовавший ранее файл с таким именем. Вторая форма отличается наличием параметра append. Если этот параметр принимает логическое значение true, записываемые данные добавляются в конец файл. В противном случае старые данные в файле перезаписываются новыми. Для того чтобы записать данные в файл, следует вызвать метод write. Наиболее простая форма этого метода приведена ниже,
void write(int byteval) throws IOException Этот метод записывает в поток байтовое значение, указанное в качестве параметра byteval. Несмотря на то что этот параметр объявлен как int, учитываются только 8 младших битов его значения. Если в процессе записи возникнет ошибка, будет сгенерировано исключение IOException. По завершении работы с файлом его нужно закрыть с помощью метода close. Объявление этого метода выглядит следующим образом:
void close throws IOException При закрытии файла освобождаются связанные с ним системные ресурсы, чтобы использовать их для работы с другим файлом. Процедура закрытия файла также гарантирует, что данные, оставшиеся в буфере, будут записаны на диск. В приведенном ниже примере программы осуществляется копирование текстового файла. Имена исходного и целевого файлов указываются в командной строке.
/ Копирование текстового файла. При вызове этой программы следует указать имя исходного и целевого файлов. Например, для копирования файла FIRST.TXT в файл SECOND.TXT в командной строке нужно указать следующее: java CopyFile FIRST.TXT SECOND.TXT / import java.io.*; class CopyFile { public static void main(String args[]) { int i; FilelnputStream fin; FileOutputStream fout; // Прежде всего следует убедиться, что оба файла были указаны, if(args.length !=2 ) { System.out.println("Usage: CopyFile From To"); return; } // открыть исходный файл try { fin = new FilelnputStream(args[0] ) ; } catch(FileNotFoundException exc) { System.out.println("Input File Not Found"); return; } // открыть целевой файл try { fout = new FileOutputStream(args[1]); } catch(FileNotFoundException exc) { System.out.println("Error Opening Output File"); // закрыть исходный файл try { fin.close ; } catch(IOException exc2) { System.out.println("Error closing input file."); } return; } // копировать файл try { do { // Чтение байтов из одного файла и запись их в другой файл. i = fin.read; if(i != -1) fout.write (i); } while(i != -1); } catch(IOException exc) { System.out.println("File Error"); } try { fin.close ; } catch(IOException exc) { System.out.println("Error closing input file."); } try { fout.close; } catch(IOException exc) { System.out.println("Error closing output file."); }