zoukankan      html  css  js  c++  java
  • 15_IO流

    IO流
    流的概念
    流(stream)是指一连串流动字节/字符,按照先进先出的方式发送的信息的通道中。
    数据源:流入通道中的数据的来源
    目的地:流出通道的数据的目的地
     
    输入流和输出流
    数据源的数据流入程序的流称为输入流
     
    程序中的数据流出到目的地的流称为输出流
     
    流的分类
     
     
    InputStream/OutputStream
    inputstream 表示字节输入流,是所有字节输入流的抽象父类。提供了read/read(byte[] buf) 用于读取一个或者多个字节;close用于关闭输入流。
     
    outputstream 表示字节输出流,是所有字节输出流的抽象父类。
    FileInputStream
    FileInputStream 专门用于读取文件的字节输入流。可以用于读取文本性文件(存在编码)、图片音频视频等二进制文件。
     
    一次读取一个字节
    package cn.sxt01.fileinputstream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    public class Test01 {
    public static void main(String[] args) {
    // 需求:读取c.txt中的内容
     
    File file = new File("d:\javatest\c.txt");
     
    // 【1】构建输入流(管道)
    FileInputStream fis = null;
     
    try {
    fis = new FileInputStream(file);
    System.out.println(fis);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
     
    // 【2】读取一个字节
    int r = 0;
    try {
    r = fis.read();
    } catch (IOException e) {
    e.printStackTrace();
    }
     
    System.out.println((char)r);
     
    // 【3】关闭流
    try {
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    read() 一次读取一个字节,如果已到达文件末尾,则返回 -1。
     
    一次读取多个字节
    package cn.sxt01.fileinputstream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.util.Arrays;
    public class Test03 {
    public static void main(String[] args) {
    // 需求:读取c.txt中的内容
     
    File file = new File("d:\javatest\c.txt");
     
    // 【1】构建输入流(管道)
    FileInputStream fis = null;
     
    try {
    fis = new FileInputStream(file);
    System.out.println(fis);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
     
    // 【2】读取一个字节
    int len = 0; // 读取到缓冲区中的字节个数
    byte[] buf = new byte[2]; // 字节缓冲区
    StringBuilder sb = new StringBuilder();
    try {
     
    while( (len=fis.read(buf)) != -1 ) {
    String tmp = new String(buf,0,len);
    sb.append(tmp);
    }
     
    } catch (IOException e) {
    e.printStackTrace();
    }
     
    System.out.println(sb);
     
    // 【3】关闭流
    try {
    fis.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    read(byte[] buf)一次读取多个字节到字节缓冲区,并返回读取的字节个数。
     
     
    FileOutputStream
     
    一次写一个字节
    package cn.sxt01.fileouputstream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    public class Test01 {
    public static void main(String[] args) {
    // 需求:写入helloworld 到d.txt中的内容
     
    File file = new File("d:\javatest\d.txt");
     
    // 【1】创建输出流(管道)
    FileOutputStream fos = null;
     
    try {
    fos = new FileOutputStream(file);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
     
    //【2】写入信息到输出流
    try {
    fos.write('h');
    fos.write('e');
    fos.write('l');
    fos.write('l');
    fos.write('o');
    } catch (IOException e) {
    e.printStackTrace();
    }
     
    // 【3】刷新缓冲区
    try {
    fos.flush();
    fos.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
     
    当调用write(int)方法时,把一个字节写入到输出流,输出流会立即把该字节写入文件中。
    所以,如果不手动代用flush方法,信息也写入到文件中。
     
    一次写多个字节(指定编码)
    package cn.sxt01.fileouputstream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    public class Test02 {
    public static void main(String[] args) {
    // 需求:写入helloworld 到d.txt中的内容
     
    File file = new File("d:\javatest\d.txt");
     
    // 【1】创建输出流(管道)
    FileOutputStream fos = null;
     
    try {
    fos = new FileOutputStream(file);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
     
    //【2】写入信息到输出流
    try {
    String str = "hello world中国";
     
    // 默认gbk编码
    /*byte[] buf = str.getBytes();
    fos.write(buf);*/
     
    byte[] buf = str.getBytes("utf8");
    fos.write(buf);
     
    } catch (IOException e) {
    e.printStackTrace();
    }
     
    // 【3】刷新缓冲区
    try {
    fos.flush();
    // 【4】关闭文件
    fos.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
     
    write(byte[] buf)一次写入多个字节到输出流。注意,此时的字节流已经经过编码。默认是系统编码(win7:gbk)。
    write(byte[] buf,offset,len) 一次写入buf中从offset开始,len个长度的字节到输出流。
     
    综合案例:
    [1]把目录中的logo.jpg复制到工程中。
    [2]请打印复制进度
     
    Reader/Writer
    Reader 是字符输入流的抽象父类。提供了read()一次读取一个字符;read(char[] buf)一次多去多个字符到字符缓冲区。
     
    Writer 是字符输出流的抽象父类。提供了
    write()写入单个字符
    write(char[] cbuf) 写入多个字符
    write(String str) 写入字符串
    FileReader
    FileReader是文件字符输入流,专门用于读取文本性文件。不能读取图片、音频、视频等二进制文件。
     
    一次读取一个字符
    package cn.sxt03.filereader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    public class Test01 {
    public static void main(String[] args) {
     
    File file = new File("d:\javatest\d.txt");
     
    // 【1】建立字符输入流
    FileReader fr = null;
    try {
    fr = new FileReader(file);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
     
    // 【2】一次读取一个字符
    int r = 0;
    try {
    /*r = fr.read();
    r = fr.read();
    r = fr.read();
    r = fr.read();
    r = fr.read();
    r = fr.read();
     
    System.out.println(r);*/
     
    /*
    中国abc
    中国你好你好
    */
    StringBuilder sb = new StringBuilder();
    while( (r=fr.read()) != -1 ) {
    sb.append((char)r);
    }
    System.out.println(sb);
     
     
    } catch (IOException e) {
    e.printStackTrace();
    }
     
    // 【3】关闭输入流
    try {
    fr.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
     
     
     
    }
    }
     
    一次读取多个字符
    package cn.sxt03.filereader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.Arrays;
    public class Test01 {
    public static void main(String[] args) {
     
    File file = new File("d:\javatest\d.txt");
     
    // 【1】建立字符输入流
    FileReader fr = null;
    try {
    fr = new FileReader(file);
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
     
    // 【2】一次读取多个字符
    int len = 0;
    char[] cbuf = new char[2];
    try {
     
    /*
    len = fr.read(cbuf);
    len = fr.read(cbuf);
    len = fr.read(cbuf);
     
    System.out.println(len);
    System.out.println(Arrays.toString(cbuf));
    */
     
    StringBuilder sb = new StringBuilder();
    while( (len=fr.read(cbuf)) != -1) {
    sb.append(cbuf, 0, len);
    }
    System.out.println(sb);
     
     
    } catch (IOException e) {
    e.printStackTrace();
    }
     
    // 【3】关闭输入流
    try {
    fr.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
     
    FileWriter
    FileWriter 文件字符输出流,专门用于写入文本性文件。
    通过FileWriter构造方法构造的对象写入文件时编码是系统默认编码(win7:gbk)。
    由于写入的是字符,字符在写入时一定要经过编码,所以FileWriter内部有一个字符缓冲区用于存放待写入的字符,在调用flush时,FileWriter把字符缓冲区的字符编码成字节然后写入目标文件。
     
    package cn.sxt03.filewriter;
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    public class Test01 {
    public static void main(String[] args) {
     
    File file = new File("d:\javatest\e.txt");
     
    FileWriter fw = null;
     
    // 【1】建立输出流管道
    try {
    /*
    * append:表示写入文件的方
    * true:追加 false:覆
    */
    fw = new FileWriter(file,false);
    } catch (IOException e) {
    e.printStackTrace();
    }
     
    // 【2】写入
    try {
     
    // 写入一个字符
    /*fw.write('中');
    fw.write('国');*/
    // 写入一个字符数组
    /*char[] cbuf = {'中','国',' ',' ','a','b','c'};
    fw.write(cbuf);*/
     
    // 写入一个字符串
    fw.write("中国abc");
     
    } catch (IOException e) {
    e.printStackTrace();
    }
     
    // 【3】刷新
    try {
    fw.flush();
    fw.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
     
    思考:如何读取一个utf8编码的文本文件。
     
    转换流
    所谓转换流可以把字节流转化成字符流的转换流
     
    InputStreamReader 是字节流通向字符流的桥梁,它使用指定的字符集读取字节并将其解码为字符。
    OutputStreamWriter 是字符流通向字节流的桥梁,可使用指定的字符集将要写入流中的字符编码成字节
     
    转换流工作原理
     
    以utf8编码写入文件
    package cn.sxt04.outputstramwriter;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;
    public class Test01 {
    public static void main(String[] args) throws FileNotFoundException,IOException {
     
    // 需求:写入 “中国abc” 以utf8编码写入
    File file = new File("d:\javatest\g.txt");
     
    FileOutputStream out = new FileOutputStream(file);
    OutputStreamWriter osw = new OutputStreamWriter(out, "utf8");
     
    osw.write('中');
    char[] cbuf = {'国','a'};
    osw.write(cbuf);
     
    osw.write("中国abc");
     
    osw.flush();
    osw.close();
    }
    }
     
    以utf8编码读取文件
    public class Test02 {
    public static void main(String[] args) throws FileNotFoundException,IOException {
     
    // 需求:读取g.txt的内容
    File file = new File("d:\javatest\g.txt");
     
    FileInputStream fis = new FileInputStream(file);
    InputStreamReader isr = new InputStreamReader(fis, "utf8");
     
    /*int r = isr.read();
    System.out.println((char)r);*/
     
    char[] cbuf = new char[2];
    int len = 0;
    StringBuilder sb = new StringBuilder();
    while( (len=isr.read(cbuf)) != -1) {
    sb.append(cbuf,0,len);
    }
    System.out.println(sb);
     
    }
    }
     
    思考:FileReader和InputStreamReader的关系?
     
    注意:win7手动创建utf8编码的文件(utf8-bom)
    java程序写入的utf8文件不带bom
    public class Test03 {
    public static void main(String[] args) throws FileNotFoundException,IOException {
     
    // 需求:读取win手动创建的utf8编码的h.txt的内容
    File file = new File("d:\javatest\h.txt");
     
    FileInputStream fis = new FileInputStream(file);
    InputStreamReader isr = new InputStreamReader(fis, "utf8");
     
    /*int r = isr.read();
    System.out.println((char)r);*/
     
    char[] cbuf = new char[2];
    int len = 0;
    StringBuilder sb = new StringBuilder();
    while( (len=isr.read(cbuf)) != -1) {
    sb.append(cbuf,0,len);
    }
    System.out.println(sb);
     
    }
    }
     
    BufferedReader/BufferedWriter
    FileReader 提供的读取字符的方式效率稍低,如果高效读写字符的方式,可以使用BufferedReader/BufferedWriter。
     
    BufferedReader
    BufferedReader继承于Reader,专门用于高效的处理文本,提供了readLine方法用于一次读取一行文本。
     
    把一首诗读取到控制台显示
    package cn.sxt01.bufferedreader;
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    public class Test01 {
    public static void main(String[] args) throws FileNotFoundException,IOException {
     
    File file = new File("d:\javatest\i.txt");
     
    // ctrl+t:查看类继承关系
    FileReader reader = new FileReader(file);
    BufferedReader br = new BufferedReader(reader);
     
    // 一次读取一行
    /*
    String str = br.readLine();
    str = br.readLine();
    str = br.readLine();
    str = br.readLine();
    str = br.readLine();
    System.out.println(str);
    */
     
     
    String line;
    while( (line=br.readLine() ) != null) {
    System.out.println(line);
    }
     
     
    br.close();
    reader.close();
    }
    }
     
     
    BufferedWriter
    BufferedWriter 是Writer的子类,专门用于高效的写入文本。提供了writer(String)和newLine()方法,写入完成后调用flush()刷新缓冲区。
    package cn.sxt01.bufferedwriter;
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.OutputStreamWriter;
    public class Test01 {
    public static void main(String[] args) throws FileNotFoundException,IOException {
     
    // 需求:以utf8存入一首诗
    File file = new File("d:\javatest\k.txt");
     
    FileOutputStream out = new FileOutputStream(file);
    OutputStreamWriter osw = new OutputStreamWriter(out, "utf8");
     
    BufferedWriter bw = new BufferedWriter(osw);
     
    bw.write("床前明月光,");
    bw.newLine();
     
    bw.write("疑似地上霜。");
    bw.newLine();
     
    bw.flush();
     
    bw.close();
    osw.close();
    out.close();
     
    }
    }
     
    标准输入输出流
     
    标准输入流
    java中用System.in表示标准输入流,属于InputStream字节输入流,标准输入设备(源):鼠标、键盘、手写板、麦克风、触摸屏等。
     
     
    需求:从键盘输入一个字符并打印出来。
    package cn.sxt02.inout;
    import java.io.IOException;
    import java.io.InputStream;
    public class Test01 {
    public static void main(String[] args) throws IOException {
     
    // 从控制台输入一个字符并打印
    InputStream in = System.in;
     
    // 【1】一次读取一个字节:(输入/数据源是键盘)
    // int r = in.read();
    // System.out.println((char)r);
     
    // 【2】一次读取多个字节
    byte[] buf = new byte[1024];
    int len = 0;
    len = in.read(buf);
     
    // 默认控制台是gbk编码
    String str = new String(buf, 0, len);
    System.out.println(str);
    }
    }
    标准输出流
    java中用System.out表示标准输出流,属于PrintStream。标准的输出设备(源):显示器、显示屏
     
    需求:从文件中读取文件内容并显示在标准输出设备上。
    package cn.sxt02.inout;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.PrintStream;
    public class Test02 {
    public static void main(String[] args) throws IOException {
     
    // 思考:为什么会乱码?
    File file = new java.io.File("d:\javatest\i.txt");
     
    FileInputStream fis = new FileInputStream(file);
     
    // 标准输出流(gbk)
    PrintStream ps = System.out;
     
    int len = 0;
    byte[] buf = new byte[2];
    while( (len=fis.read(buf)) != -1 ) {
    ps.write(buf, 0, len);
    }
     
    fis.close();
     
    }
    }
     
    通过打印流直接写入文件
    package cn.sxt02.inout;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.io.UnsupportedEncodingException;
    public class Test05 {
    public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
     
    // 通过打印流写入数据到一个文件(gbk)
    /*File file = new File("d:\javatest\m.txt");
    PrintStream ps = new PrintStream(file);
    ps.write('a');
    ps.write('b');
     
    ps.close();*/
     
     
    // 通过打印流写入一个utf8编码的文件
    File file = new File("d:\javatest\m1.txt");
    PrintStream ps = new PrintStream(file,"utf8");
    ps.println("abc中国");
     
    ps.close();
     
    }
    }
     
     
    需要flush的PrintStream
    package cn.sxt02.inout;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.PrintStream;
    import java.io.UnsupportedEncodingException;
    public class Test04 {
    public static void main(String[] args) {
     
     
    PrintStream ps = System.out;
    ps.write('a');
    ps.write('b');
     
    ps.flush();
     
    }
    }
     
    PrintStream称为打印字节流,继承于OutputStream,之前已经知道OutputStream写入文件时不需要flush。PrintStream的目的地是显示器,在PrintStream内部有个缓冲区,专门用于缓冲待输出的字节,结合显示器工作原理,当需要显示器显示待打印的字节时,需要手动调用flush方法,此时显示器才解码后显示。
     
    测试自动刷新(C)
    package cn.sxt02.inout;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.PrintStream;
    import java.io.UnsupportedEncodingException;
    public class Test04 {
    public static void main(String[] args) throws IOException {
     
    PrintStream ps = System.out;
    /*ps.write('a');
    ps.write('b');*/
     
    // 自动调用flush方
    /*byte[] buf = {'a','b'};
    ps.write(buf);*/
     
    // 自动调用flush方
    /*ps.write('a');
    ps.write('b');
    ps.write(' ');*/
     
    // 自动调用flush方
    ps.println("ab");
     
    // sps.flush();
     
    }
    }
     
     
    字符打印流
    PrintWriter 专门用于向自定目的地(显示器、文件、浏览器)中输出大量字符。继承于Writer。除了write(char)/write(char[] cbuf),还提供了特有的print/println方法用于输出各位数据类型的字符。
    public class Test01 {
    public static void main(String[] args) {
     
    // 字符输出流
    PrintWriter pw = new PrintWriter(System.out);
    pw.println("hello");
    pw.println("中国");
     
    pw.flush();
     
    pw.close();
    }
    }
     
    序列化
    把(程序)内存中的数据保存到硬盘的过程就是序列化,也称为数据持久化。
    当我们把硬盘中的数据再次读取到内存中时,这个过程就是反序列化。
     
    Serializable接口
     
    自定义类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化
     
    需求:把一个对象序列化到d:\javatest\n1.txt
     
    package cn.sxt04.serializable;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    public class Test01 {
    public static void main(String[] args) throws IOException {
     
    User user = new User("001", "二狗", "123", 20);
     
    /**
    * 思路:
    * 序列化:把对象个各个属性按照有规律的格式拼接成字符串,把字符串写入文件
    * 反序列化:把文件中的字符串读取为内存中,按序列化格式把字符串拆开得到很多属性值,然后初始化对象
    */
    // String info = user.getId()+"-"+user.getName()+"-"+user.getPwd()+"-"+user.getAge();
    // System.out.println(info);
     
    File file = new File("d:\javatest\n1.sxt");
    FileOutputStream out = new FileOutputStream(file);
    ObjectOutputStream oos = new ObjectOutputStream(out);
     
    oos.writeObject(user);
     
    oos.close();
    out.close();
     
    }
    }
     
    需求:把刚在序列化的对象反序列化
    package cn.sxt04.serializable;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    public class Test02 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
     
    File file = new File("d:\javatest\n1.sxt");
    FileInputStream in = new FileInputStream(file);
    ObjectInputStream ois = new ObjectInputStream(in);
     
    User user = (User) ois.readObject();
    System.out.println(user);
     
    }
    }
     
    序列号
    当程序在升级过程中对源代码进行修改,新代码对之前的序列化文件进行反序列化存在一个InvalidClassException异常
    Exception in thread "main" java.io.InvalidClassException: cn.sxt04.serializable.User; local class incompatible: stream classdesc serialVersionUID = 4281284299154400224, local class serialVersionUID = 8687762707351138232
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1876)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1745)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2033)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1567)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:427)
    at cn.sxt04.serializable.Test02.main(Test02.java:19)
     
    如何解决?
    始终保持本地类和序列化中文件的类的版本号一致。
    [1]默认版本号,永远是1L
    [2]手动根据类的信息(属性、方法)生成一串数字。
     
    版本号工作原理
    如果自定义类没有添加任何序列化版本号,jvm自动添加一个序列化版本号,当修改源代码时,jvm自动升级该序列化版本号,此时导致和序列化到本地文件的类版本号不一致,反序列化必将失败,抛出InvalidClassException异常。
     
    transient 关键字
    在序列化过程中,存在一些字段序列化没有意义或一些敏感自动不许序列化,可以使用transient修饰。
     
    public class User implements Serializable {
    /**
    *
    */
    private static final long serialVersionUID = 1L;
    private String id;
    private String name;
    private transient String pwd;
    private int age;
    private String phone;
     
    其他流
    DataInputStream/DataOutputStream
  • 相关阅读:
    jmeter在Windows下安装(含插件安装)
    Jenkins中agent的使用
    Jenkins自动化测试脚本的构建
    Python在Linux下编译安装
    Jenkins项目构建运行
    VIM不正常退出产生的swp文件
    SSI服务器端包含注入
    【强网杯2019】随便注
    判断网站CMS
    windows基础
  • 原文地址:https://www.cnblogs.com/aknife/p/10988089.html
Copyright © 2011-2022 走看看