Философия Java3
Шрифт:
//: io/BasicFileOutput.java
import java.io.*;
public class BasicFi1eOutput {
static String file = "BasicFileOutput out", public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader( new StringReader(
BufferedlnputFile read("BasicFileOutput java"))), PrintWriter out = new PrintWriter(
new BufferedWriter(new Fi1eWriter(fi1e))), int lineCount = 1, String s,
whi 1 e((s = in readLineO) != null )
out println(lineCount++ + " " + s). out closeO.
// Вывод содержимого файла
System out println(BufferedInputFile readCfile)).
}
} /// ~
При записи строк
Когда данные входного потока исчерпываются, метод readLine возвращает null. Для потока outl явно вызывается метод close; если не вызвать его для всех выходных файловых потоков, в буферах могут остаться данные, и файл получится неполным.
Сокращенная форма вывода текстового файла
В Java SE5 у PrintWriter появился вспомогательный конструктор. Благодаря ему вам не придется вручную выполнять всю работу каждый раз, когда вам потребуется создать текстовый файл и записать в него данные. Вот как выглядит пример BasicFileOutput.java в обновленном виде:
//• io/FileOutputShortcut java import java io *.
public class FileOutputShortcut {
static String file = "FileOutputShortcut.out", public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader( new StringReader(
BufferedlnputFile readC'FileOutputShortcut java"))); // Сокращенная запись PrintWriter out = new PrintWriter(file); int lineCount = 1, String s,
while((s = in.readLineO) != null )
out println(lineCount++ + " + s). out closeO.
// Вывод содержимого файла-
System out.printin(BufferedInputFile readCfile)); продолжение &
}
} ///;-
Буферизация по-прежнему обеспечена, но вам не приходится включать ее самостоятельно. К сожалению, для других распространенных операций сокращенной записи не предусмотрено, поэтому типичный код ввода/вывода по-прежнему содержит немало избыточного текста.
Сохранение и восстановление данных
PrintWriter форматирует данные так, чтобы их мог прочитать человек. Однако для вывода информации, предназначенной для другого потока, следует использовать классы DataOutputStream (для записи данных) и DatalnputStream (для чтения данных). Конечно, природа этих потоков может быть любой, но в нашем случае открывается файл, буферизованный как для чтения, так и для записи. Надстройки DataOutputStream и DatalnputStream ориентированы на посылку байтов, поэтому для них требуются потоки OutputStream и InputStream:
II- io/StoringAndRecoveringData.java import java io *,
public class StoringAndRecoveringData {
public static void main(String[] args) throws IOException {
DataOutputStream out = new DataOutputStream( new BufferedOutputStream(
new FileOutputStreamC'Data.txt"))); out.writeDouble(3.14159); out.writeUTFCThat was pi"); out. writeDoubled. 41413); out.writeUTFC"Square root of 2"); out.closeO;
DatalnputStream in = new DataInputStream( new BufferedlnputStreamC
new FileInputStreamCData.txt"))); System.out println(in readDoubleO). // Только readUTFO нормально читает // строки в кодировке UTF для Java; System out pri ntl n( in readUTFO); System, out. pri ntl n( in readDoubleO); System out. pri ntl n( in readUTFO);
}
} /* Output; 3.14159 That was pi 1.41413
Square root of 2 *///;-
Если
данные записываются в выходной поток DataOutputStream, язык Java гарантирует, что эти данные в точно таком же виде будут восстановлены входным потоком DatalnputStream — невзирая на платформу, на которой производится запись или чтение. Это чрезвычайно ценно, и это знает любой, так или иначе соприкасавшийся с вопросами переносимости программ. Если Java поддерживается на обеих платформах, проблема исчезает сама собой.Единственным надежным способом записать в поток DataOutputStream строку (String) так, чтобы ее можно было потом правильно считать потоком DatalnputStream, является кодирование UTF-8, реализуемое методами readUTF и writeUTF. UTF-8 — это разновидность кодировки Юникод, в которой каждый символ хранится в двух байтах. Если вы работаете только с кодировкой ASCII, «удвоение» данных в Юникоде приводит к неоправданным затратам дискового пространства и (или) нагрузке на сеть. Поэтому UTF-8 кодирует символы ASCII одним байтом, а символы из других кодировок записывает двумя или тремя байтами. Вдобавок в первых двух байтах строки хранится ее длина. Впрочем, методы readUTF и writeUTF используют специальную модификацию UTF-8 для Java23 (она описана в документации JDK), и для правильного считывания из другой программы (не на Java) строки, записанной методом writeUTF, вам придется добавить в нее специальный код, позволяющий верно ее считать.
Методы readUTF и writeUTF позволяют смешивать строки и другие типы данных, записываемые потоком DataOutputStream, так как вы знаете, что строки будут правильно сохранены в Юникоде и их будет просто воспроизвести потоком DatalnputStream.
Метод writeDouble записывает число double в поток, а соответствующий ему метод readDouble затем восстанавливает его (для других типов также существуют подобные методы). Но, чтобы правильно интерпретировать любые данные, вы должны точно знать их расположение в потоке; при наличии такой информации прочитать число double как какую-то последовательность байтов или символов не представляет сложности. Поэтому данные в файле должны иметь определенный формат, или вам придется использовать дополнительную информацию, показывающую, какие именно данные находятся в определенных местах. Заметьте, что сериализация объектов (описанная в этой главе чуть позже) часто предоставляет простейший способ записи и восстановления сложных структур данных.
Чтение/запись файлов с произвольным доступом
Как уже было замечено, работа с классом RandomAccessFile напоминает использование совмещенных в одном классе потоков DatalnputStream и DataOutputStream (они реализуют те же интерфейсы Datalnput и DataOutput). Кроме того, метод seek позволяет переместиться к определенной позиции и изменить хранящееся там значение.
При использовании RandomAccessFile необходимо знать структуру файла, чтобы правильно работать с ним. Класс RandomAccessFile содержит методы для чтения и записи примитивов и строк UTF-8. Пример:
//: io/UsingRandomAccessFile.java import java.io.*,
public class UsingRandomAccessFile { static String file = "rtest.dat". static void displayО throws IOException {
RandomAccessFile rf = new RandomAccessFile(file, "r"). for(int i =0. i <7, i++) System.out println(
"Значение " + i + " " + rf .readDoubleO); System.out.pri ntln(rf.readUTF); rf.closeO;
}
public static void main(String[] args) throws IOException {
RandomAccessFile rf = new RandomAccessFile(file, "rw"). for(int i = 0; i < 7; i++)