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.
Результатом работы программы будет:
Файл открыт для записи Записано: 3 байт Выходной поток закрыт Файл открыт для чтения Готово к считыванию: 3 байт Считано: 3 байт 1,2,3, Входной поток закрыт Пример 15.2.
При работе с FileInputStream метод available() практически наверняка вернет длину файла, то есть число байт, сколько вообще из него можно считать. Но не стоит закладываться на это при написании программ, которые должны устойчиво работать на различных платформах,– метод available() возвращает число байт, которое может быть на данный момент считано без блокирования. Тот факт, что, скорее всего, это число и будет длиной файла, является всего лишь частным случаем работы на некоторых платформах.
В приведенном примере для наглядности закрытие потоков производилось сразу же после окончания их использования в основном блоке. Однако лучше закрывать потоки в finally блоке.
... } finally { try{inFile.close();}catch(IOException e){}; }
Такой подход гарантирует, что поток будет закрыт и будут освобождены все связанные с ним системные ресурсы.
PipedInputStream и PipedOutputStream
Классы PipedInputStream и PipedOutputStream характеризуются тем, что их объекты всегда используются в паре – к одному объекту PipedInputStream привязывается (подключается) один объект PipedOutputStream. Они могут быть полезны, если в программе необходимо организовать обмен данными между модулями (например, между потоками выполнения).
Эти классы применяются следующим образом: создается по объекту PipedInputStream и PipedOutputStream, после чего они могут быть соединены между собой. Один объект PipedOutputStream может быть соединен с ровно одним объектом PipedInputStream, и наоборот. Затем в объект PipedOutputStream записываются данные, после чего они могут быть считаны именно в подключенном объекте PipedInputStream. Такое соединение можно обеспечить либо вызовом метода connect() с передачей соответствующего объекта PipedI/OStream (будем так кратко обозначать пару классов, в данном случае PipedInputStream и PipedOutputStream ), либо передать этот объект еще при вызове конструктора.
Использование связки PipedInputStream и PipedOutputStream показано в следующем примере:
try { int countRead = 0; byte[] toRead = new byte[100]; PipedInputStream pipeIn = new PipedInputStream(); PipedOutputStream pipeOut = new PipedOutputStream(pipeIn); // Считывать в массив, пока он полностью не будет заполнен while(countRead<toRead.length) { // Записать в поток некоторое количество байт for(int i=0; i<(Math.random()*10); i++) { pipeOut.write((byte)(Math.random()*127)); } // Считать из потока доступные данные, // добавить их к уже считанным. int willRead = pipeIn.available(); if(willRead+countRead>toRead.length) //Нужно считать только до предела массива