Java的IO流及IO对象的序列化整理【转】
原文地址:http://www.cnblogs.com/Bob-FD/archive/2012/09/25/2701754.html
1、什么是IO流?
byte序列的读写,Java中的IO流是实现输入/输出的基础.
Java将数据从源(文件、内存、键盘、网络)读入到内存 中,形成了流,然后将这些流还可以写到另外的目的地(文件、内存、控制台、网络),之所以称为流,是因为这个数据序列在不同时刻所操作的是源的不同部分。
2、分类
按照不同的分类标准,IO流分为不同类型。主要有以下几种方式:按照数据流方向、数据处理的单位和功能。还有一些分类比如:对象流、缓冲流、压缩流、文件流等等。其实都是节点流和处理流的子分类。不管流的分类是多么的丰富和复杂,其根源来自于四个基本的类。这个四个类的关系如下:
|
|
字节流 |
字符流 |
|
输入流 |
InputStream |
Reader |
|
输出流 |
OutputStream |
Writer |
2.1输入流与输出流。
数据从内存到硬盘,通常认为是输出流,即写操作;相反,从硬盘到内存,通常认为是输入流,即读操作;这里的输入、输出是从内存的角度划分的。
2.2字节流和字符流
字节流和字符流区别非常简单,它们的用法几乎一样。区别在于字节流和字符流所处理的最小数据单元不同。
|
|
处理最小数据单元 |
基类 |
|
字节流 |
8 |
In/OutStream |
|
字符流 |
16 |
Reader/writer |
3.3节点流和处理流
节点流是可以从或向一个特定的地方(节点)读写数据,也叫 低级流。如FileReader。
处理流是在对节点流封装的基础上的一种流,通过封装后来实现数据的读写功能,也叫高级流。
|
|
|
|
节点流 |
未经封装,low level stream |
|
处理流 |
封装过, high level stream |
常用节点流
父 类 InputStream OutputStream Reader Writer
文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件进行处理的节点流
数 组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)
字符串 StringReader StringWriter 对字符串进行处理的节点流
管 道 PipedInputStream PipedOutputStream PipedReader PipedWriter 对管道进行处理的节点流
常用处理流(关闭处理流使用关闭里面的节点流)
父 类 InputStream OutputStream Reader Writer
缓冲流 BufferedImputStrean BufferedOutputStream BufferedReader BufferedWriter
----需要父类作为参数构造,增加缓冲功能,避免频繁读写硬盘,可以初始化缓冲数据的大小,由于带了缓冲功能,所以就写数据的时候需要使用flush 方法咯 转换流 *InputStreamReader OutputStreamWriter- 要inputStream 或OutputStream 作为
参数,实现从字节流到字符流的转换数据流 *DataInputStream DataOutputStream -提供将基础数据类型写入到文件中,或者
读取出来,为什么要有这个流呢?看这样的分析,如果没有这种流的话,有一个long,本身只占8 个字节,如果我要写入到文件,需要转成字符串,然后在转成字符数组,那空间会占用很多,但是有了这种流之后就很方便了,直接将这8 个字节写到文件就完了。。是不是既节约了内存空间有让程序写起来更加方便简单了呐。写倒是很简单,但是读取的时候就注意了,根据读取的数据类型,指针会往下移,所以你写的顺序必须要和读的顺序一致才能完成正确的需求.
3.4 Java输入输出流
总结。
|
分类 |
字节输入流 |
字节输出流 |
字符输入流 |
字符输出流 |
|
抽象基类 |
InputStream |
OutputStream |
Reader |
Writer |
|
访问文件 |
FileInputStream |
FileOutputStream |
FileReader |
FileWriter |
|
访问数组 |
ByteArrayInputStream |
ByteArrayOutputStream |
CharArrayReader |
CharArrayWriter |
|
访问管道 |
PipedInputStream |
PipedOutputStream |
PipedReader |
PipedWriter |
|
访问字符串 |
|
|
StringReader |
StringWriter |
|
缓冲流 |
BufferedInputStream |
BufferedOutputStream |
BufferedReader |
BufferedWriter |
|
转换流 |
|
|
InputStreamReader |
OutputStreamWriter |
|
对象流 |
ObjectInputStream |
ObjectOutputStream |
|
|
|
抽象基类 |
FilterInputStream |
FilterOutputStream |
FilterReader |
FilterWriter |
|
打印流 |
|
PrintStream |
|
PrintWriter |
|
推回输入流 |
PushbackInputStream |
|
PushbackReader |
|
|
特殊流 |
DataInputStream |
DataOutputStream |
|
|
1)
InputStream : 抽象类读取数据的过程 包含读取方法read();
in 模仿了读取小说的过程
简单说 : in是读取文件的
OutputStream:抽象了写出数据的过程 包含写出方法write();
out模仿了写笔记记录的过程
简单说 : out是写入文件的
基本的byte流
InputStream(抽象方法read())
|--- FileInputStream(read()在文件上读取) 节点流
|
|--- FilterInputStream 过滤器流,输入流功能的扩展
| |--- DataInputStream(readInt()) 基本类型数据的读取
| |--- BufferedInputStream 提供读取缓冲区管理
| --- ObjectInputStream 过滤器流,依赖基本byte流,扩展对象的反序列化
OutputStream(抽象方法write())
|--- FileOutputStream(write()在文件上写实现写入) 节点流
|
|--- FilterOutputStream 过滤器流,输出流功能的扩
| |--- DataOutputStream(writerInt()) 基本类型数据的写出
| |--- BufferedOutputStream 提供了输出缓冲区管理
| --- ObjectOutputStream 过滤器流,依赖基本byte流,扩展对象的序列化
注意:除节点流外都是过滤器流
字符流,可以处理字符编码,底层依赖于byte流
Reader 读取文本
| --- InputStreamReader 过滤去,依赖基本byte输入流
| 实现文本编码的解析
|
| --- BufferedReader 过滤器, 需要依赖Reader 实例
| 提供了readLine()方法, 可以在文本文件中读取一行
| 是常用的文本读取方法
Writer
| --- OutputStreamWriter 过滤器,,依赖基本byte输出流
| 实现文本编码
| --- PrintWriter 过滤器,依赖于Writer 流
| 提供了输出文本常有方法println()
2) EOF = End of File = -1 (文件读到末尾会返回-1)
3) 输入流的基本方法
InputStream in = new InputStream(file) / /file是文件名
int b = in.read(); 读取一个byte无符号填充到int底八位,-1是EOF
int.read(byte[] buf) 读取数据填充到buf中
int.read(byte[] buf,int start,int size) 读取数据填充到buf中
in.close 关闭输入流
4)输出流的基本方法:
OutputStream out = new OutputStream(file) / /file是文件名
out.write(int b) 写出一个byte 到流 b 的底八位写出
out.write(byte[] buf) 将buf的一部分写入流中
out.write(byte[] buf, int start, int size) 将buf的一部分写入流中
out.flush() 清理缓存
out.close
1.FileInputStream (read()在文件上读取) 节点流
方法: read() 从输入流中读取数据的下一个字节
read(byte[] buf) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 buf中
read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。
例
1 import java.io.FileInputStream;
2 import java.io.IOException;
3 import java.io.InputStream;
4
5 public class InputStreamDemo {
6 public static void main(String[] args)
7 throws IOException {
8 String file = "out.txt";
9 InputStream in = new FileInputStream(file);
10 int b;
11 while((b=in.read())!=-1){//read()方法
12 System.out.print(Integer.toHexString(b) + " ");
13 }
14 in.close();
15
16 in = new FileInputStream(file);
17 //in.available() 可以读取的数据个数,小文件一般是文件长度
18 byte[] buf = new byte[in.available()];
19 in.read(buf);//read(byte[] buf)方法重载
20 in.close();
21 for (byte c : buf) {
22 System.out.print(Integer.toHexString(c & 0xff) + " ");
23 // c & 0xff --->将16进制写成0xff的格式
24 //ffffffd6---> d6
25 //11111111 11111111 11111111 11010110 &对应相乘
26 //00000000 00000000 00000000 11111111 0xff
27 //00000000 00000000 00000000 11010110
28 }
29 }
30 }
2 FileOutputStream(write()在文件上写实现写入) 节点流
方法 :write(int b) 将指定的字节写入此输出流。
write(byte[] buf) 将 b.length 个字节从指定的 byte 数组写入此输出流。
write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
例子
1 import java.io.*;
2
3 public class OutputStreamDemo {
4 public static void main(String[] args)
5 throws IOException{
6 String file = "out.txt";
7 OutputStream out = new FileOutputStream(file);
8 out.write(65);//在文件中是以16进制存储的,对应0x41
9 out.write(66);//0x42
10 byte[] buf = {(byte)0xd6,(byte)0xd0};
11 out.write(buf);
12 out.flush();//刷出缓存,清理缓冲区,保证可靠写
13 out.close();
14 }
15 }
3.BufferedInputStream和BufferedOutputStream 的 用法
BufferedInputStream(FileInputStream in)
BufferedOutputStream(FileOutputStream out)
可以提高性能
例子
1 import java.io.BufferedInputStream;
2 import java.io.BufferedOutputStream;
3 import java.io.FileInputStream;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.InputStream;
7
8 public class BufferedStreamDemo {
9 public static void main(String[] args) throws IOException {
10 //BufferedInputStream普通写法
11 String file = "out.txt";
12 InputStream ins = new FileInputStream(file);
13 BufferedInputStream bufin= new BufferedInputStream(ins);
14 int b;
15 while((b=bufin.read())!=-1){
16 System.out.println(Integer.toHexString(b));
17 }
18 //常用写法,只要用到FileInputStream的地方都可以套一个BufferedInputStream用来提升性能
19 BufferedInputStream in = new BufferedInputStream(
20 new FileInputStream("out.txt"));
21
22 //BufferedOutputStream
23 BufferedOutputStream out = new BufferedOutputStream(
24 new FileOutputStream("out.txt"));
25 out.write(65);
26 }
27 }
4.基本类型数据的写出和读入
DataOutputStream 方法:readInt() readLong() readBoolean()等
写出(写)
1 例子
2 import java.io.*;
3 public class DataOutDemo {
4 public static void main(String[] args)
5 throws IOException{
6 String file = "data.dat";//项目文件夹
7 OutputStream out = new FileOutputStream(file);
8 //DataOutputStream 实现基本类型数据的序列化
9 //将基本类型数据拆开为byte序列,写入到out流中
10 DataOutputStream dos = new DataOutputStream(out);
11 dos.write(-2);
12 dos.writeInt(-2);
13 dos.writeLong(-2);
14 dos.writeByte(-2);
15 dos.writeDouble(-2);
16 dos.writeShort(-2);
17 dos.writeFloat(-2);
18 dos.writeBoolean(true);
19 dos.writeChar('中');
20 dos.close();
21
22 }
23 }
DataInputStream 方法: writeInt() writeChar() 等8种
读入(读)
1 import java.io.DataInputStream;
2 import java.io.FileInputStream;
3 import java.io.IOException;
4 import java.io.InputStream;
5
6 public class DataInDemo {
7 public static void main(String[] args)
8 throws IOException{
9
10 String file = "data.dat";
11
12 InputStream in = new FileInputStream(file);
13 //DataInputStream 从基本流中读取基本类型数据,实现基本
14 //类型数据的反序列化
15 DataInputStream dis = new DataInputStream(in);
16 int b = dis.read();
17 int i = dis.readInt();
18 long l= dis.readLong();
19 byte bx = dis.readByte();
20 double d = dis.readDouble();
21 short s = dis.readShort();
22 float f = dis.readFloat();
23 boolean bol = dis.readBoolean();
24 char c = dis.readChar();
25 dis.close();
26 System.out.print( b +" ");//254 fe
27 System.out.print(i+" ");
28 System.out.print(l+" ");
29 System.out.print(bx+" ");
30 System.out.print(d+" ");
31 System.out.print(s+" ");
32 System.out.print(f+" ");
33 System.out.print(bol+" ");
34 System.out.print(c+" ");
35
36 }
37 }
5 字符串的序列化(文字的编码方案)
从char序列到byte序列 的转换,叫"编码"
1) String 字符串本质上是Char
2)utf-16be 编码-----将16位char从中间切开为2个byte
utf -16be是将 unicode char[] 序列化为byte[]的编码方案
能够支持65535个字符编码,英文浪费空间
如:
char[] = ['A', 'B', '中']
对应 0041,0042,4e2d
utf-8:国际标准,是将unicode编码为byte序列的方案,采用变长编码 1-N方案,其中英文1个byte,中文3个byte
unicoded的" 中": 4e 2d = 01001110 00101101
utf-8的"中":e4 b8 ad =11100100 10111000 10101101
1110xxxx 10xxxxxx 10xxxxxx
以0开头的是英文(0-127)
110表示连续2字节表示一个字符
1110表示连续3字节表示一个字符
每个数据字节以10开头
GBK: 中国标准,支持20000+中日韩文,英文编码1byte,中文2byte
与unicode不兼容,中文windows默认gbk
ISO8859-1:只支持255个英文字符,不支持中文(Sun服务器默认编码,如tomcat等)
例子
1 import java.io.FileOutputStream;
2 import java.io.IOException;
3 import java.io.OutputStream;
4
5 public class CharIODemo {
6 public static void main(String[] args)
7 throws IOException{
8 String str = "ABCD中国";
9 System.out.println(str);
10 //Java 的字符是16位 Unicode值,而文件是8位Byte序列
11
12 //GBK
13 System.out.println("GBK编码方案,对字符编码");
14 String file = "gbk.txt";
15 OutputStream out = new FileOutputStream(file);//默认GBK编码方案
16 byte[] gbk = str.getBytes("GBK");
17 out.write(gbk);
18 out.close();
19 IOUtils.print(file);
20 //UTF-16BE,每个编码是2个字节
21 System.out.println("UTF-16BE编码方案,对字符编码");
22 file = "utf-16be.txt";
23 out = new FileOutputStream(file);
24 byte[] utf16be = str.getBytes("UTF-16BE");
25 out.write(utf16be);
26 out.close();
27 IOUtils.print(file);
28
29 //UTF-8,英文是1个字节,中文是3个字节
30 System.out.println("UTF-8编码方案,对字符编码");
31 file = "utf-8.txt";
32 out = new FileOutputStream(file);
33 byte[] utf8 = str.getBytes("UTF-8");//编码string -> byte[]
34 out.write(utf8);
35 out.close();
36 IOUtils.print(file);
37
38 byte[] buf = IOUtils.read("utf-8.txt");
39 //new String(buf,"UTF-8"),构造器可以将 byte编码序列
40 //解码为 char序列(字符串)
41 String s = new String(buf,"UTF-8");//解码byte-> String
42 System.out.println(s);
43 }
44 }
6 字符流IO(Reader Writer)
1) 字符的处理,一次处理一个字符(unicode编码)
2) 字符的底层仍然是基本的字节流
3) 字符流的基本实现
InputStreamReader 完成byte流解析为char流,按照编码解析
OutputStreamWriter 提供char流到byte流,按照编码处理
4) 字符流的过滤器
是字符读写的功能扩展,极大的方便了文本的读写操作
BufferedReader : readLine() 一次读取一行
PrintWriter : println() 一次打印一行
5)读取一个文本文件
InputStream is = new FileInputStream("test.txt");
Reader in = new InputStreamReader(is);
BufferedReader reader = new BufferedReader(in);
或者
BufferedReader in = new BufferedReader(new FileReader(filename));
例子:
1 import java.io.BufferedInputStream;
2 import java.io.BufferedReader;
3 import java.io.FileInputStream;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6
7 public class TestReaderDemo {
8 public static void main(String[] args)
9 throws IOException{
10 //Scanner BufferedReader都是流的功能扩展,是过滤器
11 // 不能单独使用,最终需要依赖于基本byte流(in)
12 //Scanner 提供了nextLine()方法//Java5以后
13 //BufferedReader 提供了 readLine()方法,读取一行
14 //readLine()读取到文件末尾返回null
15
16 //逐行读取文本文件,显示到系统控制台
17 //工作中常用
18 String file = "in.txt"; //为当前工作区workspace/项目名/in.txt
19 BufferedReader in = new BufferedReader(
20 new InputStreamReader(
21 new BufferedInputStream(
22 new FileInputStream(file)),"gbk"));
23 String str;
24 while((str = in.readLine()) != null){
25 System.out.println(str);
26 }
27 in.close();
28 }
6)写出一个文本文件
PrintWriter out = new PrintWriter(new FileWriter(new FileOutputStream(filename)));
或者
PrintWriter out = new PrintWriter(
new OutputStreamWriter(
new FileOutputStream(filename)))
例子
1 import java.io.IOException;
2 import java.io.PrintWriter;
3 import java.util.Scanner;
4
5 public class SyncWriteDemo {
6 public static void main(String[] args)
7 throws IOException{
8 Scanner in = new Scanner(System.in);
9 String file = "sync.txt";
10 PrintWriter out = new PrintWriter(file,"UTF-8");
11 while(true){
12 String str = in.nextLine();
13 out.println(str);
14 if("q".equalsIgnoreCase(str)){
15 break;
16 }
17 }
18 out.close();
19 }
20 }
7)系统的默认编码,中文一般是GBK
如何查看默认编码?
String encoding = System.getProperty("file.encoding");
7 对象的IO序列化和深层复制
什么是对象序列化:
将对象Object转换为byte序列,反之叫做对象的反序列华
1)序列化流,是过滤流
ObjectOutputStream 方法 writeObject() 对象的序列化
ObjectInputStream 方法readObject() 对象的反序列化
2)序列化接口(Serializable)
对象必须实现"序列化接口Serializable"才能进行序列化,否则将出现不能序列化的异常
Serializable是一个空的接口,没有任何方法 ,仅作为序列化的一个标识
3)JavaBean 规范规定,Java类必须实现Serializable接口
Java API中的类大多是符合Java Bean规范的,基本都实现了Serializable
4) 对象的序列化可以变相实现对象的深层复制
例子
1 import java.io.BufferedInputStream;
2 import java.io.BufferedOutputStream;
3 import java.io.FileInputStream;
4 import java.io.FileOutputStream;
5 import java.io.ObjectInputStream;
6 import java.io.ObjectOutputStream;
7 import java.io.Serializable;
8
9 public class ObjectIODemo {
10 public static void main(String[] args)
11 throws Exception{
12 String file = "obj.dat";
13 ObjectOutputStream out = new ObjectOutputStream(
14 new BufferedOutputStream(
15 new FileOutputStream(file)));
16 Foo foo =new Foo();
17 out.writeObject(foo);//将foo引用的对象,序列化到文件中
18 out.close();
19
20 //读出
21 ObjectInputStream in = new ObjectInputStream(
22 new BufferedInputStream(
23 new FileInputStream(file)));
24 Foo foo1 = (Foo)in.readObject();//对象反序列化
25 in.close();
26 System.out.println(foo1.name);
27
28 System.out.println("深层复制:对象被复制,对象属性也被复制");
29 System.out.println(foo==foo1);//false 对象复制了(一层)
30 System.out.println(foo.name == foo1.name);//false ,属性被复制了(二层)
31 //利用序列化 和 反序列化 可以简洁的实现 对象的深层复制
32 }
33
34 }
35 class Foo implements Serializable{//Serializable没有声明方法
36 String name = "Tom";
37 }
浅层复制与深层复制
1)java的默认规则是浅层复制,性能好,但隔离性差,如(clone(),Arrays.copyOf)
浅层复制 : 对象的引用不同,但对象中属性的引用相同
2)利用序列化可以实现深层复制
深层复制: 对象的引用不同,但对象中的属性的引用也不相同
例
1 import java.io.ByteArrayInputStream;
2 import java.io.ByteArrayOutputStream;
3 import java.io.ObjectInputStream;
4 import java.io.ObjectOutputStream;
5
6 public class DeepcopyDemo {
7 public static Object deepCope(Object obj){
8 try{
9 //1. 对象序列化
10 // 缓冲流: 字节数组输出流
11 ByteArrayOutputStream buf =
12 new ByteArrayOutputStream();
13 //对象输出流
14 ObjectOutputStream out =
15 new ObjectOutputStream(
16 new ByteArrayOutputStream());
17
18 out.writeObject(obj);//序列化对象到buf中
19 out.close();
20
21 //2 .对象的反序列化
22 byte[] ary = buf.toByteArray();
23 ByteArrayInputStream bais =
24 new ByteArrayInputStream(ary);
25 ObjectInputStream in =
26 new ObjectInputStream(bais);
27 Object o = in.readObject();//从ary反序列化
28 in.close();
29 return o;
30
31 }catch(Exception e){
32 e.printStackTrace();
33 throw new RuntimeException(e);
34 }
35 }
36 }
以上用到的ByteArrayInputStream和ByteArrayOutputStream
下面有一个ByteArrayInputStream和ByteArrayOutputStream的例子
例子
1 import java.io.ByteArrayInputStream;
2 import java.io.ByteArrayOutputStream;
3 import java.io.IOException;
4 import java.util.Arrays;
5
6 import com.tarena.day18.IOUtils;
7
8 public class ByteArrayIODemo {
9 public static void main(String[] args)
10 throws IOException{
11 byte[] ary = {1,-1,127,-128};
12 // {00000001, 11111111, 01111111, 10000000}
13 ByteArrayInputStream in = new ByteArrayInputStream(ary);
14 int b = in.read();//1 00000000 00000000 00000000 00000001
15 System.out.println(b);
16 b = in.read();
17 System.out.println(b);//255 00000000 00000000 00000000 11111111
18 b = in.read();
19 System.out.println(b);//127 00000000 00000000 00000000 01111111
20 b = in.read();
21 System.out.println(b);//128 00000000 00000000 00000000 10000000
22 b = in.read();
23 System.out.println(b);//-1 11111111 11111111 11111111 11111111
24 in.close();
25
26 ByteArrayOutputStream out = new ByteArrayOutputStream();//默认开辟32byte的数组作为输出目标
27 //如果满了就自动扩容
28 //out:[0,0,0,0,0,0,0,.....]
29 //
30 out.write(1);//[1,0,0,0,0,0,....]
31 out.write(-2);//[1,fe,0,0,0,0,0,....]
32 out.write(-1);//[1,fe,ff,0,0,0,0,....]
33 out.close();
34 byte[] buf = out.toByteArray();//复制有效部分
35 IOUtils.print(buf);//[01, fe, ff ]
36 }
37
38 }
39
40
41
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


浙公网安备 33010602011771号