前言
Java I/O类分成输入和输出两部分,字节输入、输出类都继承自InputStream、OutputStream,字符输入、输出类都继承自Reader、Writer。
输入输出是以内存为参照的,将外部文件读入内存中叫做输入(Input&Read),将数据写入外部文件中叫做输出(Output&Write)。
1.字节流读写文件
首先将内容写入一个文件中,使用FileOutPutStream
。
String dir = "F:/technology/filedir/rwdir/";
//输出文件至磁盘中,使用字节方式输出
FileOutputStream fos = null;
try {
fos = new FileOutputStream(dir+"poem.txt");
byte[] bytes = new byte[3];
bytes[0] = 0x64;
bytes[1] = 0x0D;
bytes[2] = 0x0A;
fos.write(bytes);
String poem1 = "小时不识月,呼作白玉盘。\r\n";
fos.write(poem1.getBytes(Charset.forName("GBK")));
String poem2 = "国破山河在,城春草木深。\r\n";
fos.write(poem2.getBytes(Charset.forName("GBK")));
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(fos!=null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
成功将内容写入文件,如下所示:
再将文件用字节流方式读出,FileInputStream
。
String dir = "F:/technology/filedir/rwdir/poem.txt";
//读入内存中,打印出来
FileInputStream fis = null;
try {
fis = new FileInputStream(dir);
//用以存放读取的字节
byte[] bytes = new byte[64];
if(fis.read(bytes)==64){
//等于64表示可能还有数据未读取完
return;
};
System.out.println(new String(bytes,"GBK"));
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(fis!=null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
结果如下图所示。
可以从上面的示例看到用字节流读取文本字符串非常麻烦,不但要大概估计文本字节的长度,还要考虑编码的影响,所以字节流读写比较适用于图片类文件。
2.怎么写就怎么读的数据存储/恢复方式
用DataOutputStream
写入数据,并用DataInputStream
恢复数据,两者配合可以精确的读取到对应的数据。
先用DataOutputStream
写入内容至文件dataformat.txt
中.
String filePath = "F:/technology/filedir/rwdir/dataformat.txt";
DataOutputStream dos = null;
try {
//创建格式输出流
dos = new DataOutputStream(new FileOutputStream(filePath));
//只取前8位,后24位省略不计
dos.write(130);
//同上
dos.writeBoolean(false);
dos.writeByte(10);
//自动转换为ASCII 字符a
dos.writeChar(97);
dos.writeInt(66);
dos.writeLong(1900);
dos.writeFloat(1.3f);
dos.writeDouble(9.9);
dos.writeUTF("Hello World!");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(dos!=null)
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
显示结果如下图,可以看到除了字符和字符串其它都不能按照原意正常显示。
再用DataInputStream
将之读出
String filePath = "F:/technology/filedir/rwdir/dataformat.txt";
DataInputStream dis = null;
try {
//创建格式输出流
dis = new DataInputStream(new FileInputStream(filePath));
System.out.println(dis.read());
System.out.println(dis.readBoolean());
System.out.println(dis.readByte());
System.out.println(dis.readChar());
System.out.println(dis.readInt());
System.out.println(dis.readLong());
System.out.println(dis.readFloat());
System.out.println(dis.readDouble());
//读取字符串
System.out.println(dis.readUTF());
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(dis!=null)
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
读取结果
之前保存的数据准备地读取了出来,但一定要注意读取的顺序要跟之前写入的顺序一样,否则就会读出错误的数据。对于读写复杂的数据,对象序列化和XML是更合适的方式。
3.字符串的读写
从上面格式化的读写可以发现,输出的文本有可能会存在解码问题无法阅读,为解决这个问题,引入了Reader和Writer两个接口,用于处理16位的国际化Unicode字符,它可以轻松地输入输出文本信息。
写字符串入文件中
String filePath = "F:/technology/filedir/rwdir/string.txt";
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(filePath));
bw.write("天生我材必有用,千金散尽还复来。");
bw.newLine();
bw.write("天若有情天亦老,人间正道是沧桑。");
bw.newLine();
bw.write("好雨知时节,当春乃发生。");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(bw!=null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
文本内容如下
从文件中读出字符串
String filePath = "F:/technology/filedir/rwdir/string.txt";
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(filePath));
StringBuilder sb = new StringBuilder();
String s=null;
while ((s = br.readLine())!=null){
sb.append(s);
}
System.out.println(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}finally {
if(br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果如下:
使用Reader/Writer读写文本十分方便,并且不用担心造成乱码问题,另使用缓冲能显著增加I/O操作的性能。