Программирование на Java
Шрифт:
Когда работа с потоком закончена, его следует закрыть. Для этого вызывается метод close. Этот метод сначала освобождает буфер (вызовом метода flush ), после чего поток закрывается и освобождаются все связанные с ним системные ресурсы. Закрытый поток не может выполнять операции вывода и не может быть открыт заново. В классе OutputStream реализация метода close не производит никаких действий.
Итак, классы InputStream и OutputStream определяют необходимые методы для работы с байтовыми потоками данных. Эти классы являются абстрактными. Их задача – определить общий интерфейс для классов,
Классы-реализации потоков данных
Классы ByteArrayInputStream и ByteArrayOutputStream
Самый естественный и простой источник, откуда можно считывать байты, – это, конечно, массив байт. Класс ByteArrayInputStream представляет поток, считывающий данные из массива байт. Этот класс имеет конструктор, которому в качестве параметра передается массив byte[]. Соответственно, при вызове методов read возвращаемые данные будут браться именно из этого массива. Например:
byte[] bytes = {1,-1,0};
ByteArrayInputStream in =
new ByteArrayInputStream(bytes);
int readedInt = in.read; // readedInt=1
System.out.println("first element read is: "
+ readedInt);
readedInt = in.read;
// readedInt=255. Однако
// (byte)readedInt даст значение -1
System.out.println("second element read is: " + readedInt);
readedInt = in.read;
// readedInt=0 System.out.println("third element read is:
" + readedInt);
Если запустить такую программу, на экране отобразится следующее:
first element read is: 1
second element read is: 255
third element read is: 0
При вызове метода read данные считывались из массива bytes, переданного в конструктор ByteArrayInputStream. Обратите внимание, в данном примере второе считанное значение равно 255, а не -1, как можно было бы ожидать. Чтобы понять, почему это произошло, нужно вспомнить, что метод read считывает byte, но возвращает значение int, полученное добавлением необходимого числа нулей (в двоичном представлении). Байт, равный -1, в двоичном представлении имеет вид 11111111 и, соответственно, число типа int, получаемое приставкой 24-х нулей, равно 255 (в десятичной системе). Однако если явно привести его к byte, получим исходное значение.
Аналогично, для записи байт в массив применяется класс ByteArrayOutputStream. Этот класс использует внутри себя объект byte[], куда записывает данные, передаваемые при вызове методов write. Чтобы получить записанные в массив данные, вызывается метод toByteArray. Пример:
ByteArrayOutputStream out =
new ByteArrayOutputStream;
out.write(10);
out.write(11);
byte[] bytes = out.toByteArray;
В этом примере в результате массив bytes будет состоять из двух элементов: 10 и 11.
Использовать классы ByteArrayInputStream и ByteArrayOutputStream
Классы FileInputStream и FileOutputStream
Класс FileInputStream используется для чтения данных из файла. Конструктор такого класса в качестве параметра принимает название файла, из которого будет производиться считывание. При указании строки имени файла нужно учитывать, что она будет напрямую передана операционной системе, поэтому формат имени файла и пути к нему может различаться на разных платформах. Если при вызове этого конструктора передать строку, указывающую на несуществующий файл или каталог, то будет брошено java.io.FileNotFoundException. Если же объект успешно создан, то при вызове его методов read возвращаемые значения будут считываться из указанного файла.
Для записи байт в файл используется класс FileOutputStream. При создании объектов этого класса, то есть при вызовах его конструкторов, кроме имени файла, также можно указать, будут ли данные дописываться в конец файла, либо файл будет перезаписан. Если указанный файл не существует, то сразу после создания FileOutputStream он будет создан. При вызовах методов write передаваемые значения будут записываться в этот файл. По окончании работы необходимо вызвать метод close, чтобы сообщить системе, что работа по записи файла закончена. Пример:
byte[] bytesToWrite = {1, 2, 3};
byte[] bytesReaded = new byte[10];
String fileName = "d:\\test.txt";
try {
// Создать выходной поток FileOutputStream
outFile = new FileOutputStream(fileName);
System.out.println("Файл открыт для записи");
// Записать массив outFile.write(bytesToWrite);
System.out.println("Записано: " + bytesToWrite.length + " байт");
// По окончании использования должен быть закрыт
outFile.close;
System.out.println("Выходной поток закрыт");
// Создать входной поток
FileInputStream inFile = new FileInputStream(fileName);
System.out.println("Файл открыт для чтения");
// Узнать, сколько байт готово к считыванию
int bytesAvailable = inFile.available;
System.out.println("Готово к считыванию: " + bytesAvailable + " байт");
// Считать в массив
int count = inFile.read(bytesReaded,0,bytesAvailable);
System.out.println("Считано: " + count + " байт");
for (int i=0;i<count;i++) System.out.print(bytesReaded[i]+",");
System.out.println;
inFile.close;
System.out.println("Входной поток закрыт");
}
catch (FileNotFoundException e) {
System.out.println("Невозможно произвести запись в файл: " + fileName);
}
catch (IOException e) {
System.out.println("Ошибка ввода/вывода: " + e.toString);
}
Пример 15.1.
Результатом работы программы будет: