Буферизованный ввод/вывод




Файловый ввод/вывод

Поскольку файлы в большинстве современных операционных систем понимаются как последовательность байтов, для файлового ввода/вывода создаются байтовые потоки с помощью классов Fiieinputstream и FiieOutputstream. Это особенно удобно для бинарных файлов, хранящих байт-коды, архивы, изображения, звук.

Но очень много файлов содержат тексты, составленные из символов. Несмотря на то, что символы могут храниться в кодировке Unicode, эти тексты чаще всего записаны в байтовых кодировках. Поэтому и для текстовых файлов можно использовать байтовые потоки. В таком случае со стороны программы придется организовать преобразование байтов в символы и обратно.

Чтобы облегчить это преобразование, в пакет java.io введены классы FileReader и FileWriter. Они организуют преобразование потока: со стороны программы потоки символьные, со стороны файла — байтовые. Это происходит потому, что данные классы расширяют классы InputStreamReader и OutputstreamWriter, соответственно, значит, содержат "переходное кольцо" внутри себя.

Несмотря на различие потоков, использование классов файлового ввода/вывода очень похоже.

В конструкторах всех четырех файловых потоков задается имя файла в виде строки типа String или ссылка на объект класса File. Конструкторы не только создают объект, но и отыскивают файл и открывают его. Например:

FileInputStream fis = new FilelnputStream(“PrWr.Java");

FileReader fr = new FileReader("D:\\jdkl.3\\src\\PrWr.Java");

При неудаче выбрасывается исключение класса FileNotFoundException, но конструктор класса FileWriter выбрасывает более общее исключение IOException.

После открытия выходного потока типа FileWriter или FileOutputStEeam содержимое файла, если он был не пуст, стирается. Для того чтобы можно было делать запись в конец файла, и в том и в другом классе предусмотрен конструктор с двумя аргументами. Если второй аргумент равен true, то происходит дозапись в конец файла, если false, то файл заполняется новой информацией. Например:

FileWriter fw = new FileWriter("ch!8.txt", true);

FileOutputStream fos = new FileOutputStream("D:\\samples\\newfile.txt");

Внимание

Содержимое файла, открытого на запись конструктором с одним аргументом, стирается.

Сразу после выполнения конструктора можно читать файл:

fis.read(); fr.read();

или записывать в него:

fos.write((char)с); fw.write((char)с);

По окончании работы с файлом поток следует закрыть методом close ().

Преобразование потоков в классах FileReader и FileWriter выполняется по кодовым таблицам установленной на компьютере локали. Для правильного ввода кирилицы надо применять FileReader, a нe FileInputStream. Если файл содержит текст в кодировке, отличной от локальной кодировки, то придется вставлять "переходное кольцо" вручную, как это делалось для консоли, например:

InputStreamReader isr = new InputStreamReader(fis, "KOI8_R"));

Байтовый поток fis определен выше.

Получение свойств файла

В конструкторах классов файлового ввода/вывода, описанных в предыдущем разделе, указывалось имя файла в виде строки. При этом оставалось неизвестным, существует ли файл, разрешен ли к, нему доступ, какова длина файла.

Получить такие сведения можно от предварительно созданного экземпляра класса File, содержащего сведения о файле.

В конструкторе этого класса File(String filename)

указывается путь к файлу или каталогу, записанный по правилам операционной системы. В UNIX имена каталогов разделяются наклонной чертой /, в MS Windows — обратной наклонной чертой \, в Apple Macintosh — двоеточием:. Этот символ содержится в системном свойстве file.separator (см. рис. 6.2). Путь к файлу предваряется префиксом. В UNIX это наклонная черта, в MS Windows — буква раздела диска, двоеточие и обратная наклонная черта. Если префикса нет, то путь считается относительным и к нему прибавляется путь к текущему каталогу, который хранится в системном свойстве user.dir.

Конструктор не проверяет, существует ли файл с таким именем, поэтому после создания объекта следует это проверить логическим методом exists ().

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

Прежде всего, логическими методами isFile(), isDirectory() можно выяснить, является ли путь, указанный в конструкторе, путем к файлу или каталогу.

Для каталога можно получить его содержимое — список имен файлов и подкаталогов— методом list(), возвращающим массив строк string[]. Можно получить такой же список в виде массива объектов класса File[] методом listFiles(). Можно выбрать из списка только некоторые файлы, реализовав интерфейс FileNameFilter и обратившись к методу

list(FileNameFilter filter).

Если каталог с указанным в конструкторе путем не существует, его можно создать логическим методом mkdir(). Этот метод возвращает true, если каталог удалось создать. Логический метод mkdirs() создает еще и все несуществующие каталоги, указанные в пути.

Пустой каталог удаляется методом delete ().

Для файла можно получить его длину в байтах методом length(),время последнеймодификации в секундах с 1 января 1970 г. методом lastModified(). Если файл не существует, эти методы возвращают нуль.

Логические методы canRead (), canWrite () показывают права доступа к файлу.

Файл можно переименовать логическим методом renameTo(File newName) или удалить логическим методом delete(). Эти методы возвращают true, если операция прошла удачно.

Если файл с указанным в конструкторе путем не существует, его можно создать логическим методом createNewFilet), возвращающим true, если файл не существовал, и его удалось создать, и false, если файл уже существовал.

Статическими методами

createTempFile(String prefix, String suffix, File tmpDir)

createTempFile(String prefix, String suffix)

можно создать временный файл с именем prefix и расширением suffix в каталоге tmpDir или каталоге, указанном в системном свойстве java.io.tmpdir (см. рис. 6.2). Имя prefix должно содержать не менее трех символов. Если suffix = null, то файл получит суффикс.tmp.

Перечисленные методы возвращают ссылку типа File на созданный файл. Если обратиться к методу deieteOnExit (), то по завершении работы JVM временный файл будет уничтожен.

Несколько методов getxxxo возвращают имя файла, имя каталога и другие сведения о пути к файлу. Эти методы полезны в тех случаях, когда ссылка на объект класса File возвращается другими методами и нужны сведения о файле. Наконец, метод toURL () возвращает путь к файлу в форме URL.

В листинге 18.2 показан пример использования класса File, а на рис. 18.4 — начало вывода этой программы.

Листинг 18.2. Определение свойств файла и каталога

import java.io.*;

class FileTest{

public static void main(String[] args) throws IOException{

PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out, "Cp866"), true);

File f = new File("FileTest.Java");

pw.println();

pw.println("Файл \"" + f.getName() + "\" " +

(f.exists()?"":"не ") + "существует");

pw.println("Вы " + (f.canRead()?"":"не ") + "можете читать файл");

pw.println("Вы " + (f.canWrite()?"":"нe ") +

"можете записывать в файл");

pw.println("Длина файла " + f.length() + " б");

pw.println();

File d = new File(" D:\\jdkl.3\\MyProgs ");

pw.println("Содержимое каталога:");

if (d.exists() && d.isDirectory()) {

String[] s = d.list();

for (int i = 0; i < s.length; i++)

pw.println(s[i]); } } }

 

Рис. 18.4. Свойства файла и начало вывода каталога

Буферизованный ввод/вывод

Операции ввода/вывода по сравнению с операциями в оперативной памяти выполняются очень медленно. Для компенсации в оперативной памяти выделяется некоторая промежуточная область — буфер, в которой постепенно накапливается информация. Когда буфер заполнен, его содержимое быстро переносится процессором, буфер очищается и снова заполняется информацией.

Житейский пример буфера — почтовый ящик, в котором накапливаются письма. Мы бросаем в него письмо и уходим по своим делам, не дожидаясь приезда почтовой машины. Почтовая машина периодически очищает почтовый ящик, перенося сразу большое число писем. Представьте себе город, в котором нет почтовых ящиков, и толпа людей с письмами в руках дожидается приезда почтовой машины.

Классы файлового ввода/вывода не занимаются буферизацией. Для этой цели есть четыре специальных класса BufferedXxx, перечисленных выше. Они присоединяются к потокам ввода/вывода как "переходное кольцо", например:

BufferedReader br = new BufferedReader(isr);

BufferedWriter bw = new BufferedWriter(fw);

Потоки isr и fw определены выше.

Программа листинга 18.3 читает текстовый файл, написанный в кодировке СР866, и записывает его содержимое в файл в кодировке KOI8_R. При чтении и записи применяется буферизация. Имя исходного файла задается в командной строке параметром args[0], имя копии — параметром argstl].

Листинг 18.3. Буферизованный файловый ввод/вывод

import java.io.*;

class DOStoUNIX{

public static void main(String[] args) throws IOException{

if (args.length!= 2){

System.err.println("Usage: DOStoUNIX Cp866file KOI8_Rfile");

System.exit(0); }

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(args[0]), "Cp866"));

BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(newFileOutputStream(args[1]),”KOI8_R"));

int с = 0;

while ((c = br.read())!= -1)

bw.write((char)c);

br.close(); bw.close();

System.out.println("The job's finished."); } }



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2020-05-09 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: