zoukankan      html  css  js  c++  java
  • 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 }

    以上用到的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 
    40 
    41  
  • 相关阅读:
    spring学习之@SessionAttributes
    Spring MVC @SessionAttributes注解
    SpringBoot yml 配置 多配置文件,开发环境,生产环境配置文件分开
    java 常用集合list与Set、Map区别及适用场景总结
    JAVA中String.format的用法 格式化字符串,格式化数字,日期时间格式化,
    Spring注解详解@Repository、@Component、@Service 和 @Constroller
    使用idea 在springboot添加本地jar包的方法本地运行有效,一旦需要打jar就会报错,这就需要在
    使用idea 在springboot添加本地jar包的方法 部署的时候本地jar没有包含的解决方法
    IDEA 快速将spring boot项目打包成jar包,简单快速有效
    java 泛型详解-绝对是对泛型方法讲解最详细的,没有之一
  • 原文地址:https://www.cnblogs.com/hqr9313/p/2467294.html
Copyright © 2011-2022 走看看