您的位置:首页 > 编程语言 > Java开发

Java核心类库——IO原理和用法

2015-02-28 09:48 204 查看
Java IO流(InputStream/OutputSteam)

什么是IO流?

byte序列的读写,Java中的IO流是实现输入/输出的基础.

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 }


以上用到的ByteArrayInputStreamByteArrayOutputStream

下面有一个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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: