好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

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  }

以上用到的 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   

分类:  java

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于Java核心类库——IO原理和用法的详细内容...

  阅读:29次