传统IO总结-14年写的
Posted coolgame
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了传统IO总结-14年写的相关的知识,希望对你有一定的参考价值。
上面是IO家族的全家福,这里先讲一下InputStream和OutputStream。
字节流InputStream和OutputStream
一个我们日常开发常见的场景,复制文件,应该如何实现?一般的,我们会使用InputStream的read方法从源文件读取数据,然后用OutputStream的write方法向目标文件写数据。
读写部分的代码是这样的:
try{
//构造一个输入流对象(读数据)source.txt文本的内容为: 呵呵呵呵呵
InputStream is = new FileInputStream("F:\\source.txt");
//构造一个输出流对象(写数据)
OutputStream os = new FileOutputStream("F:\\target.txt");
int len;//表示读入的数据(十进制的形式表示)
while((len = is.read())!=-1){
System.out.println("len="+len);
os.write(len);
}
os.close();
is.close();
}catch(Exception e){
e.printStackTrace();
}
byte是基本类型的一种,八位,取值范围是‘1000 0000‘到‘0111 1111‘(这是补码),转换成十进制是‘-128‘到‘127‘。
int也是基本类型的一种,三十二位,取值范围-2147483648到2147483647。代码里,读取一字节(byte)的数据,然后返回的是一个十进制的数字(int),因为int有32位,所以接收只有8位的byte简直绰绰有余,把这个十进制数字作为参数传给write,在write方法里自然会还原成对应的byte数据,写到目标文件里。这样,复制就完成了。其实,InputStream有三个重载的read方法。它们是:
1.read():一次读取一个字节;返回一个int,读到文件末尾返回-1;
2.read(byte [] b):一次读取一个byte数组长度的数据;返回一个int,读到文件末尾返回-1,这个int代表的是实际读取的字节个数,如果数组长度是1024,在数据足够的情况下,返回值都是1024,代表read方法读取了1024个字节。读取到的数据都存放在数组b中,可以通过OutputStream的write(b)方法写到目标文件中。
3.read(byte[] b,int off,int len):将输入流中最多 len 个数据字节读入字节数组。尝试读取多达 len 字节,但可能读取较少数量。以整数形式返回实际读取的字节数。将读取的第一个字节存储在元素 b[off] 中,下一个存储在 b[off+1] 中,依次类推。读取的字节数最多等于 len。
这里说一下native关键字,native方法是指本地方法,当在方法中调用一些不是由java语言写的代码或者在方法中用java语言,直接操纵计算机硬件时要声明为native方法,java中,通过JNI(Java Native Interface,java本地接口)里实现。FileInputStream的read方法就是native的,据说是交给c库实现了。
OutputStream有三个重载的write方法。参数形式和InputStream是一样的,不说了。
FileInputStream和FileOutputStream
因为操作文件,所以要使用FileInputStream和FileOutputStream,它们重写了父类的方法。这里说一点,new
FileOutputStream("文件路径/文件名"),如果文件路径存在,文件不存在,则会根据文件名创建文件。如果文件路径不存在,则会报错。(可以修改参数,决定FileOutputStream是否替换已存在文件)。
最后说一句,如果你要复制文件,一个字节一个字节的copy是很慢的。
BufferedInputStream和BufferedOutputStream
这两货是缓冲流,存在就是为了提高读写速率的,各有一个8K(默认的)的缓冲区。可以这样使用它们:
try{
InputStream is = new FileInputStream("F:\\source.txt");
OutputStream os = new FileOutputStream("F:\\target.txt");
InputStream bis = new BufferedInputStream(is);
OutputStream bos = new BufferedOutputStream(os);
int len;//表示读入的数据(十进制的形式表示)
while((len = bis.read())!=-1){
System.out.println ("len="+len);
bos.write(len);
}
bos.close();
bis.close();
}catch(Exception e){
e.printStackTrace();
}
可以这样理解,BufferedInputStream一次读取8K的数据到内存中(如果有这么多数据),然后向BufferedOutputStream中写8K数据,当达到8K,BufferedOutputStream会一次将这8k数据从内存写到目标文件里。因为大大减少了将数据从硬盘copy到内存的次数(一个字节一个字节读写,文件里有多少个字节就要copy多少次,学过操作系统的同学知道,这是很浪费时间的),所以节省了大把的时间。需要注意的是,可以通过BufferedOutputStream的flush方法送出不足8k的数据。当然,关闭流也可以达到相同效果。另外,关闭上层的流,下层的流也会同时关闭,所以代码里不用再关闭FileInputStream和FileOutputStream了。
DataInputStream和DataOutputStream
如果要求你向文件中写入boolean类型,你要怎么做?首先,你要知道true和false的二进制编码是什么,然后通过字节流可以将2进制编码写入文件。当读取的时候,你要判断不同的二进制编码是什么意思,才可以把文件中的二进制编码还原成true和false。很麻烦,用数据流可以解决这个问题。
代码如下:
try {
File file = new File("F:\\source.txt");
DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
out.writeBoolean(true);
out.writeByte((byte) 121);
out.writeChar((char) ‘爱‘);
out.writeShort((short) 100);
out.writeInt(300);
out.writeLong(100000000000000L);
out.writeUTF("你好");
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
使用代码读取文件中的内容:
try {
File file = new File("F:\\source.txt");
DataInputStream in = new DataInputStream(new FileInputStream(file));
System.out.println("readBoolean():"+ in.readBoolean());
System.out.println("readByte():"+in.readByte());
System.out.println("readChar():"+in.readChar());
System.out.println("readShort():"+in.readShort());
System.out.println("readInt():"+in.readInt());
System.out.println("readLong():"+in.readLong());
System.out.println("readUTF():"+ in.readUTF());
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
输出结果如下:
据我观察,write和read是一一对应关系。你在文件里写入的是一长串二进制数据,其中有Int、byte、boolean,当你读取的时候,也要按照写入的顺序去读取,否则是读不出准确的数据的。
PS:请看source.txt文件里存储的内容 :
ObjectInputStream和ObjectOutputStream
要求你向文件中写入java中的对象,怎么办。用这两个家伙吧,它们存在的意义和DataInputStream与DataOutputStream是一样的。
写数据:
try {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("F:/source.txt"));
out.writeBoolean(true);
out.writeByte((byte)65);
out.writeChar(‘a‘);
out.writeInt(20131015);
out.writeFloat(3.14F);
out.writeDouble(1.414D);
// 写入HashMap对象
HashMap map = new HashMap();
map.put("one", "red");
map.put("two", "green");
map.put("three", "blue");
out.writeObject(map);
// 写入自定义的Box对象,Box实现了Serializable接口
Box box = new Box("desk", 80, 48);
out.writeObject(box);
out.close();
} catch (Exception ex) {
ex.printStackTrace();
}
读取代码:
try {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("F:/source.txt"));
System.out.printf("boolean:%b\n" , in.readBoolean());
System.out.printf("byte:%d\n" , (in.readByte()&0xff));
System.out.printf("char:%c\n" , in.readChar());
System.out.printf("int:%d\n" , in.readInt());
System.out.printf("float:%f\n" , in.readFloat());
System.out.printf("double:%f\n" , in.readDouble());
// 读取HashMap对象
HashMap map = (HashMap) in.readObject();
Iterator iter = map.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry)iter.next();
System.out.printf("%-6s -- %s\n" , entry.getKey(), entry.getValue());
}
// 读取Box对象,Box实现了Serializable接口
Box box = (Box) in.readObject();
System.out.println("box: " + box);
in.close();
} catch (Exception e) {
e.printStackTrace();
}
我只想说,完全可以用理解DataInputStream与DataOutputStream的方式去理解这两个流。
System.out.println()
先看看System的源码:
public final class System {
public final static PrintStream out = null;
...
}
我们知道了,syso实际上调用的是PrintStream的println方法。
字符流Reader和Writer
首先讲一下字节流和字符流的区别:
读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
结论:只要是处理纯文本数据,就优先考虑使用字符流。
除此之外都使用字节流。
我们主要使用Writer的write方法和Reader的read方法。下面介绍它们的具体子类。
InputStreamReader和OutputStreamWriter
既然是处理字符的,首先一个问题就是如何编码。
private static void testWrite() {
try {
File file = new File("f:/source.txt");
OutputStreamWriter out = new OutputStreamWriter(
new FileOutputStream(file), "utf-8");
out.write("哈哈哈啊哈哈哈呀呀");
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void testRead() {
try {
File file = new File("f:/source.txt");
InputStreamReader in = new InputStreamReader(new FileInputStream(file), "utf-8");
char c1 = (char) in.read();
System.out.println("c1=" + c1);
//跳过2个字符
in.skip(2);
char c2 = (char) in.read();
System.out.println("c2=" + c2);
// 测试read(char[] cbuf, int off, int len)
char[] buf = new char[2];
in.read(buf, 0, buf.length);
System.out.println("buf=" + (new String(buf)));
//循环方式读取
int b;
while((b=in.read())!=-1){
System.out.println("@"+(char)b);
}
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
source.txt里的内容:
因为我这个source.txt就是用的utf-8编码,所以文件里面的内容不是乱码~~~
BufferedReader、BufferedWriter和PrintWriter
这三个流是处理字符串的,有了它们终于可以成行的读写了,欢呼~
private static void testWrite() {
try {
File file = new File("f:/source.txt");
OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(file), "utf-8");
PrintWriter pw = new PrintWriter(out);
//BufferedWriter bw = new BufferedWriter(out);
pw.println("我说我写的手都麻了你信么?");
pw.append("啊!");
pw.write("反正我信了!");
//bw.newLine();
//bw.write("O(∩_∩)O哈哈~");
pw.close();
//bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void testRead() {
try {
File file = new File("f:/source.txt");
InputStreamReader in = new InputStreamReader(new FileInputStream(file), "utf-8");
BufferedReader br = new BufferedReader(in);
String str = "";
while((str=br.readLine())!=null){
System.out.println(str);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
输出:
只能算是简单的总结吧,写累了,不写了。
@font-face { font-family: "宋体"; }@font-face { font-family: "宋体"; }@font-face { font-family: "@宋体"; }@font-face { font-family: "Cambria"; }@font-face { font-family: "Monaco"; }p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0cm 0cm 0.0001pt; text-align: justify; font-size: 12pt; font-family: Cambria; }a:link, span.MsoHyperlink { color: blue; text-decoration: underline; }a:visited, span.MsoHyperlinkFollowed { color: purple; text-decoration: underline; }.MsoChpDefault { font-family: Cambria; }div.WordSection1 { }
以上是关于传统IO总结-14年写的的主要内容,如果未能解决你的问题,请参考以下文章