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

来源:互联网 发布:群抢红包软件 编辑:程序博客网 时间:2024/05/18 05:02

from http://www.cnblogs.com/hqr9313/archive/2012/04/23/2467294.html

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---> d625    //11111111 11111111 11111111 11010110  &对应相乘26    //00000000 00000000 00000000 11111111  0xff27    //00000000 00000000 00000000 1101011028   }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);//0x4210   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   //BufferedOutputStream23   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  fe27   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   //GBK13   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-> String42   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()读取到文件末尾返回null15   16   //逐行读取文本文件,显示到系统控制台17   //工作中常用18   String file = "in.txt"; //为当前工作区workspace/项目名/in.txt19   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 0000000115   System.out.println(b);16   b = in.read();17   System.out.println(b);//255   00000000 00000000 00000000 1111111118   b = in.read();   19   System.out.println(b);//127   00000000 00000000 00000000  0111111120   b = in.read();21   System.out.println(b);//128   00000000 00000000 00000000  1000000022   b = in.read();23   System.out.println(b);//-1    11111111  11111111  11111111  1111111124   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  

0 0
原创粉丝点击