Java处理文本I/O
使用Scanner类读取文本数据,使用printWrite类写文本数据
File对象封装了文件或路径属性,但不包含从/向文件读/写的方法,
为了进行I/O操作,需要使用正确的Java I/O类创建对象。这些对象包含对文件操作的方法
例:将文本写入一个temp.txt文件中,使用PrintWrite类创建一个对象
PrintWrite output = new PrintWrite("temp.txt");
//调用对象的print方法来写入数据
output.print("java");
//关闭文件
output.close();
java有许多用于各种目的的I/O类。通常可以将它们分为输入类和输出类。输入类包含读数据的方法,输出类包含写数据的方法
例:为文件创建一个输入对象,并从该文件中读取数据
Scanner input = new Scanner("temp.txt");
//读取文件一行的内容,以换行结束
System.out.println(input.nextLine());
输入对象从文件读取数据流,输出对象将数据流写入文件。输入对象也成为输入流(input stream),输出对象也成为输出流(output stream)
文本I/O与二进制I/O
计算机并不区分文本文件和二进制问价。所有文件都是以二进制形式来存储的。文本I/O建立在二进制I/O的基础上。它能提供一种抽象,用于字符的编码或解码,在写入字符时,Java虚拟机将会将Unicode码转为文件特定的编码,读取字符时又会将特定编码转为Unicode码
二进制I/O不需要转化;如过用二进制I/O写入一个数值,就是将内存中的值复制到文件中。由于二进制I/O不需要编码和解码,所以效率是比文本要高。二进制文件与主机的编码无关,因此是可移植的。任何机器上的Java程序都可以通过读取Java程序所创建的二进制文件。Java类文件可以在任何具有Java虚拟机的机器上运行
二进制I/O
Java的I/O类的公共操作在父类中泛化定义,而子类提供特定的操作。InputStream类是二进制输入类的根类,OutputStream是二进制输出类的根类
java.io.InputStream | |
---|---|
read():int | 从输入流读取下一个字段,如果到达流的最后没有可读字节,返回值-1 |
read(b: byte[]): int | 从输入流读取b.length个字节到数组b中,返回实际读取到的字节数。到流的最后返回-1 |
read(b: byte[], off: int, len: int):int | 从输入流读取字节并将它们保存在b[off] … b[off + len-1]中。返回实际字节数。到流的最后返回-1 |
close(): void | 关闭输入流,释放占用的任何系统资源 |
skip(n: long): long | 从输入流中跳过并丢弃n字节的数据。返回实际跳过的字节数 |
OutputStream剩下的方法与上面类似
fulsh(): void 清除输出流,强制写出任何缓冲的输出字节
FileInputStream与FileOutputStream
这两个类用于对文件的读写。所用的方法都是从父类那里继承的没有引入新的方法
构造一个FileInputStream对象:
FileInputStream(file: File)//从一个File对象创建一个FileInputStream
FileInputStream(filename:String)//从文件名创建一个FileInputStream
构造一个FileOutputStream对象,若该文件不存在,就会创造一个新的文件 。若文件已经存在,前两个构造方法将会删除文件的当前内容。后两个方法将其中的append参数设置为true便可以保留现有内容并追加新数据。
FileOutputStream(file: File);
FileOutputStream(filename:String);
FileOutputStream(file: File, append: boolean);
FileOutputStream(filename:String, append: boolean);
几乎所有的I/O类中的方法都会抛出异常java.io.IOException,因此必须在方法中声明该异常或者将代码放到try-catch块中。
public class TestFileStream{
public static void main(string[] args) throws IOException{
//为temp.dat构造一个对象
try(FileOutputStream ouput = new FileOutputStream("temp.dat")){
for(int i = 0;i<10;i++){
ouput.write(i);
}
try(FileInputStream input = new FileInputStream("temp.dat")){
int value;
//使用父类的read方法,当没有可读的字节返回-1
for(value = input.read() != -1){
System.out.print(value + " ");
}
}
}
}
这里使用了try-with-resources来声明和创建输入输出流,这个语法可以自动关闭文件
try(声明和创建资源){//资源必须是AutoCloseable的子类型
使用资源处理文件;
}
FileInputStream类的实例可以作为参数来构造一个Scanner对象,那么它的输出类的实例也可以作为参数来构造一个Scanner对象。若是文件不存在则创建这个文件并写入数据
(虽然我还不知道这有什么用。。。暂时!暂时!)
new PrintWrite(new FileOutputStream("temp.txt",true));
FilterInputStream与FilterOutputStream
过滤器数据流(file stream) 是为某种目的过滤字节的数据流。基本字节输入流提供的read只能读取字节,若是读取整形,双精度或字符串就需要一个过滤器类来包装字节输入流。FilterInputStream和FilterOutputStream类就是用于过滤数据的基类。
DataInputStream与DataOutputStream
DataInputStream从数据流中读取字节,将它们转换为合适的基本类型或字符串
DataOutputStream则相反,将基本数据转为字节,将字节输出到流
这两个类都实现了相应的接口,实现了读取和写入基本数据类型与字符串。基本数据类型不需要做任何转化就可以从内存中复制到数据流
DataInputStream过滤字节输入流并将其转化为基本类型值和字符串
《interface》 java.io.DataInput | |
---|---|
readBoolean(): boolean | 从输入流中读取一个Boolean值 |
readByte(): byte | 从数据流中读取一个byte值 |
readChar(): char | 读取一个字符 |
readFloat(): float | 读取一个float值 |
readDouble(): double | 读取一个double值 |
readInt(): int | 读取一个int值 |
readLong(): long | 读取一个long值 |
readShort(): short | 读取一个short值 |
readLine(): string | 从输入流中读取一行字符 |
readUTF(): string | 以UTF的格式读取一个字符串 |
DataOutputStream将基本数据类型和字符串写入输出流
《interface》 java.io.DataOutput | |
---|---|
writeBoolean(b: boolean): void | 向输出流写一个Boolean值 |
writeByte(v: int): void | 向输出流写参数v的低八位 |
writeBytes(s: String): void | 向输出流写字符串中字符的低位字节 |
writeChar(c: char): void | 向输出流写一个字符(由两个字节组成) |
writeChars(s: String) :void | 向输出流中依次写字符串s中的每个字符,每个两个字节 |
writeFloat(v: float): void | 写一个float值 |
writeDouble(v: double): void | 写一个double值 |
writeInt(V: int): void | 写一个int值 |
writeLong(v: long): void | 写一个long值 |
writeShort(v: short): void | 写一个short值 |
writeUTF(String s): void | 以UTF的格式写一个字符串s |
二进制I/O中的字符与字符串
writeChar(char c)/(String s)是将字符c/字符串s的Unicode码写入输入流;writeByte(String s)将字符串s中每个字符的低位字节写到输入流,高位字节被丢弃;writeBytes适用于由ASCII字节码构成的字符串,ASCII仅存储Unicode码的低位字节,如果字符中包含非ASCII码的字符,必须使用writeChars方法写入。
writeUTF(String s)使用UTF编码模式写一个字符串。UTF对于压缩使用Unicode字符的字符串是非常高效的。readUTF()可以读取用writeUTF写入的字符串。
创建DataInputStream和DataOutputStream类
创建数据流:
//为in.dat文件创建一个输入流
DataInputStream input = new DataInputStream(new FileInputStream("in.dat"));
//为out.dat文件创建一个输出流
DataOutputStream output = new DataOutputStream(new FileOUtputStream("out.dat"));
例:将学生名字和分数写入名为temp.dat文件中,然后将数据从文件中读取出来
import java.io.*;
public class TestDataStream {
//抛出IOException异常
public static void main(String[] args) throws IOException {
//使用try-with-resources来创建输入输出流
try (DataOutputStream output = new DataOutputStream(new FileOutputStream("temp.dat"))){
output.writeUTF("张三");
output.writeDouble(86.7);
output.writeUTF("李四");
output.writeDouble(77.9);
output.writeUTF("张王五");
output.writeDouble(90.2);
}
try(DataInputStream input = new DataInputStream(new FileInputStream("temp.dat"))){
System.out.println(input.readUTF() + " " + input.readDouble());
System.out.println(input.readUTF() + " " + input.readDouble());
System.out.println(input.readUTF() + " " + input.readDouble());
}
}
}
运行结果:
DataInputStream与DataOutputStream以机器无关的方式读写java基本类型值和字符串,因此在一个机器上写好文件也可以在另一台操作系统不同的机器或文件结构的机器上读取该文件
DataInputStream <——FileInputStream<——External File //从文件读取数据输入流的工作过程
DataOutputStream——>FileOutputStream——>External File //写入数据输出流的工作过程
读取文件数据应该按照存入数据时的顺序和格式来读写读取数据
如果到达InputStream的末尾之后还继续从中读取数据,会产生EOFException异常,可以用catc块来捕获该异常
BufferedInputStream与BufferedOutputStream
这两个类可以通过减少磁盘读写次数来提高输入和输出速度。使用BufferedInputStream时,磁盘上的整块数据一次性地读入内存的缓冲区中,然后从缓冲区将单个数据传递到程序中;使用BufferedOutputStream时单个数据首先写入缓冲区,当缓冲区装满时将其中的所有数据一次性写入磁盘中
这两个类也没有新方法,都是继承了InputStream和OutputStream;这两个类在后台管理了一个缓冲区,根据需求自动将从磁盘中读取数据和写入数据
如果没有指定缓冲区的大小,那么默认大小就是512个字节
将上面TestDataStream中的输入输出流加上缓冲提高效率
//输出流加入缓冲
DataOutputStream output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("temp.dat")));
//输入流加入缓冲
DataInputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream("temp.dat")));