Java

Java IO流

JAVA_IO.png

分类

  • java按照将流连接类型分为

    • 节点流(低级流):是实际连接数据源与程序的“管道”,负责实际读写数据的流,读写一定是建立在节点流的基础上进行的
    • 处理流(高级流):不能独立存在,必须连接在其他流上,目的是当数据“流经”当前流时对其进行加工处理,简化我们读写时对数据的相应操作
  • 按流的方向分为

    • 输入流:InputStream
    • 输出流:OutputStream (所有字节流的超类)
  • 按照处理字节单位分为

    • 字节流:InputStream和OutputStream
    • 字符流:Reader和Writer

常用的IO流:

  1. 文件流 FileOutputStream(路径/File对象)-FIS 和FileInputStream(路径/File对象)-FOS
  2. 对象流 ObjectOutputStream(fos)-OOS 和ObjectInputStream(fis)-OIS
  3. 字节缓冲流 BufferedOutputStream(fos)-BOS 和BufferedInputStream(fos)-BIS
  4. 字符转换流 OutputStreamWriter(fos)-OSW 和InputStreamReader(fis)-ISR
  5. 字符缓冲流 BufferedWriter(osw)-BW 和BufferedReader(isr)-BR
  6. 字符缓冲加速流 PrintWriter(bw)-PW

1. 文件流

  • java.io.FileInputStream
  • java.io.FileOutputStream

常用的一类低级流的实现类,用来来接文件
对文件进行读写操作(功能上与RAF一致,但都有各自的优缺点)

文件输入流的常用构造方法

  • FileInputStream(File file)
  • FileOutputStream(String path)

    上面两种构造方法创建的文件输入流为覆盖模式
    即:若文件存在则文件数据清除,然后通过当前流写入的数据作为新数据保存

  • FileOutputStream(File file,boolean append)
  • FileOutputStream(String path,boolean append)

    以上两种构造方法创建的文件输入流为追加模式
    即:若文件存在,则数据保留,当前流写入的内容会顺序追加到文件末尾

示例1 利用文件输出流写文件

package io;

import java.io.FileOutputStream;
import java.io.IOException;

public class FOSDemo {
    public static void main(String[] args) throws IOException{
        FileOutputStream fos = new FileOutputStream("./fos.txt",true);
        String line = "记得双击嬷嬷哒";
        byte[] data = line.getBytes("gbk");
        
        fos.write(data);
        System.out.println("写入完毕");
        
        fos.close();
    }
}

示例2 利用文件输入流读文件

package io;

import java.io.FileInputStream;
import java.io.IOException;

/**
 * 文件输入流,用于读取文件数据
 * 
 * 文件流与RAF放入区别
 * 1:RAF是基于指针的随机读写,读写方式更灵活
 * 并且可以对文件部分内容覆盖进行编辑操作
 * 而文件流则不行,文件流是基于java标准IO
 * 的操作方式,而IO读写为顺序读写,
 * 即只能向后读写操作不能回退
 * 
 * 2:文件流可以借助流连接完成复杂
 * 读写操作,这一点是RAF做不到的
 * @author QAIU
 *
 */
public class FISDemo {
    public static void main(String[] args) throws IOException{
        FileInputStream fis = new FileInputStream("fos.txt");
        byte[] data = new byte[100];
        int len = fis.read(data);
        System.out.println("实际读取到了:"+len+"字节");
        /*
         * String(byte[] data,int offset,int len,string csn)
         * 将给定的字符数组中
         * 将给定字符数组从下标offset
         * 处的连续len个字节按照指定的字符集转为字符串
         */
        String line = new String(data,0,len,"gbk");
        System.out.println(line);
    }
}

示例3 复制文件

package io;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

使用文件流完成文件复制操作
@author QAIU

public class CopyDemo {
    public static void main(String[] args) throws IOException{
                1.创建文件输入流读取源文件
        2.创建文件输出流写复制文件
        3.循环读写,完成复制
        
        
        FileInputStream fis = new FileInputStream("\\jdk api 1.8_China");
        FileOutputStream fos = new FileOutputStream("out.exe");
        
        byte[] data = new byte[102];
        int len = -1;
        while((len = fis.read(data))!=-1) {
            fos.write(data, 0, len);
        }
        System.out.println("复制完毕");
    }
}

2. 字节缓冲流

  • java.io.BufferedOutputStream
  • java.io.BufferedInputStream

缓存字节输入输出流 是一对高级流,
在流连接的作用是提高读写效率(内部维护了一个8K的字节数组,
并将读写的数据转换成块读写从而提高效率)

使用缓冲流复制文件

package io;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;


public class CopyDemo2 {
    public static void main(String[] args) throws IOException{
        FileInputStream fis = new FileInputStream("D:\\jdk api 1.8_China\\使用说明.docx");
        FileOutputStream fos = new FileOutputStream("使用说明1.docx");
        
        BufferedInputStream bif = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        
        int data = -1;
        while((data = bif.read())!=-1) {
            bos.write(data);
        }
        System.out.println("复制完毕!");
        bif.close();
        bos.close();
    }
}

3. 对象流

java.io.ObjectOutputStream
java.io.ObjectInputStream
对象流是一对高级流,作用是将java对象与字节
进行相互转换,便于我们读写java对象

对象输出流提供的方法:
void writeObject(Object obj)

将对象按照其结构转换一组字节并写出
写出对象所属的类必须实现Serializable接口
否则写出时会抛出异常
一个对象转出字节后会发现比该对象实际存储的数据要大
这是因为这组字节除了包含当前对象的数据外 还要记录对象的
结构信息以便于还原

这里涉及到两个专业术语:

  1. 将一个对象经过对象流写出时,对象流会按照其结构将该对象转换成一组字节,这个过程叫做对象序列化
  2. 这组被序列化后的字节在经过文件流写入文件(写入磁盘)做长久保存的过程 叫做数据持久化

对象输出流示例

Person.java:

package io;

import java.io.Serializable;
import java.util.Arrays;

/**
 * 使用当前类实例测试 对象流的读写操作
 * @author QAIU
 */
public class Person implements Serializable{
    
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    private String gender;
    private transient String[] otherInfo;
    
    public Person(String name, int age, String gender, String[] otherInfo) {
        super();
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.otherInfo = otherInfo;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getGender() {
        return gender;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public String[] getOtherInfo() {
        return otherInfo;
    }
    public void setOtherInfo(String[] otherInfo) {
        this.otherInfo = otherInfo;
    }
    @Override
    public String toString() {
        return name+","+age+","+gender+","+Arrays.toString(otherInfo);
    }
    
}

OOSDemo.java:

package io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class OOSDemo {
    public static void main(String[] args) throws IOException{
        String name = "小坤坤";
        int age = 18;
        String gender = "男";
        String[] outerInfo = {"学生","中国","喜欢唱跳篮球rap"};
        
        Person p = new Person(name, age, gender, outerInfo);
        FileOutputStream fos = new FileOutputStream("person.obj");
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        oos.writeObject(p);
        System.out.println("写出完毕");
        oos.close();
        
    }
}

使用对象输入流 反序列化

package io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class OISDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException{
        FileInputStream fis = new FileInputStream("person.obj");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Object object = ois.readObject();
        System.out.println(object);
        ois.close();
    }
}

4. 转换流

java将按照读写单位分为:字节流和字符流
字节流:以字节为单位,一次至少读写8位二进制
字符流:以字符为单位读写数据,由实际读写的字节量与
指定的字符集与读写的字符数据有关 但是在java内部表示字符数据时都是用char表示(2字节)

  • java.io.Writer
  • java.io.Reader

上面两个类是抽象类,是所有字符输出流和字符输入流的超类
里面规定了读写字符相关的方法

转换流(字节流转字符流),他们是字符流的一对常用实现类,是一对高级流
实际开发中我们在读写文本数据时,它们是流连接中重要的一环
但是我们不会直接操
Java提供了这样一对转换流

  • OutputStreamWriter: 是字符流通向字节流的桥梁
  • InputStreamReader: 从字节流到字符流的桥梁

使用转换输出流写文本信息

package io;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class OSWDemo {
    public static void main(String[] args) throws IOException{
        FileOutputStream fos = new FileOutputStream("osw.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
        /*
         * 转换流在创建时通过指定第二个参数来确
         * 定字符集,这样通过当前流写出文本时
         * 都会按照该字符集转换为字节后再做写出
         */
        String string = "是兄弟就来砍我~~~~~~";
        osw.write(string);
        
        osw.close();
        System.out.println("输出完毕");
    }
}

使用转换输入流读文本信息

package io;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * java.io.InputStreamReader
 * 转换流--输入
 * 
 * InputStreamReader与OutputStreamWriter之所以
 * 称为转换流是因为:
 * 通常java中其他的高级字符流都只能连接在其他字符
 * 流上,都不能直接连接字节流.但是它们是可以连接在
 * 字节流上的,而本身又是字符流,这样就可以让其他的
 * 字符流与字节流衔接了,起到了"转换器"的作用.
 * 
 * @author QAIU
 *
 */
public class ISRDemo {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("./src/io/ISRDemo.java");
        
        InputStreamReader isr = new InputStreamReader(fis);
        
        int d = -1;
        while((d = isr.read())!=-1) {
            System.out.print((char)d);
        }
        isr.close();
    }
}

5. 字符缓冲流和缓冲加速(字符打印)流

  • java.io.BufferedWriter
  • java.io.BufferedReader

以上两个就是缓冲字符输入与输出流是一对高级流,内部有缓冲区,读写文本数据效率高

  • java.io.PrintWriter

内部总是连接BufferedWriter作为缓冲加速使用
并且PW还支持自动刷新功能,实际开发比较常用

PrintWriter提供了对文件直接写操作的构造器

  • PrintWriter(File file)
  • PrintWriter(String path)

并且上面的构造器还支持一个重载PrintWriter(String fileName, String csn),第二个参数
是字符集名称,这样可以按照指定的字符集名称写出文本数据

使用缓冲字符输入流读取文件

package io;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 缓冲字符输入流
 * 特点:块读写效率高,并且可以按行读取字符串
 * @author QAIU
 *
 */
public class BRDemo {
    public static void main(String[] args) throws IOException{
        FileInputStream fis = new FileInputStream("./src/io/BRDemo.java");
        
        BufferedReader br = new BufferedReader(new InputStreamReader(fis));
        /*
         * String readline()
         * 返回一行字符串,缓冲流会将一行字符串
         * (到换行符"\n"为止,但不包括"\n")的内容
         * 返回,若返回值为null,则表示流已经读取到了末尾
         */
        String line = null;
        while((line = br.readLine())!=null) {
            System.out.println(line);
        }
        br.close();
    }
}

使用字符打印流写文件

package io;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;


public class PWDemo {
    public static void main(String[] args) throws IOException {
        PrintWriter pw = new PrintWriter("pw.txt","GBK");
        pw.println("写入换行");
        pw.print("不换行");
        pw.println("换行了");
        pw.close();
    }
}

在流连接中使用PW

package io;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class PWDemo2 {
    public static void main(String[] argv) throws IOException {
        FileOutputStream fos = new FileOutputStream("pw2.txt");
        OutputStreamWriter osw = new OutputStreamWriter(fos);
        BufferedWriter bw = new BufferedWriter(osw);
        PrintWriter pw = new PrintWriter(bw);
        pw.println(123*3);
        
        pw.close();
        
        
    }
}

缓冲输出流的缓冲区问题

package io;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class BOS_flushDemo {
    public static void main(String[] args) throws IOException{
        FileOutputStream fos = new FileOutputStream("bos.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        
        String str = "测试文本";
        bos.write(str.getBytes("GBK"));
        /*
         * void flush()
         * 该方法是OutputStream定义的方法,
         * 但并非所有字节输出流都实现了该方法的功能
         * 只有缓冲流的该方法有实际意义
         * 作用是一次性将缓冲区已存在的数据写出
         * 之所以所有的字节流都有该方法是因为
         * 流连接应用中缓冲流通常不是"终端流"(直接被我们操作的流)
         * 为了传递刷新缓冲区功能才有
         */
        bos.flush();
        System.out.println("写入完毕");
        bos.close();
        
    }
}

综合应用 简易记事本工具

package io;

import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Scanner;

/**
 * 简易记事本工具
 * 程序启动后要求用户输入文件名,之后将用户输入
 * 的每一行字符串按行写入该文件,单独输入exit
 * 时退出
 * 使用PW完成按行写入文本数据操作
 * 要求 独立完成流连接操作
 * @author QAIU
 *
 */
public class Note {
    public static void main(String[] args) throws IOException{
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入文件名");
        String filename = scanner.nextLine();

        PrintWriter pw = new PrintWriter(
                new BufferedWriter(
                        new OutputStreamWriter(
                            new FileOutputStream(filename),"gbk")),true);

        System.out.println("请输入每一行文本,按exit退出");

        String str;
        while(!"exit".equals(str = scanner.nextLine())) {
            pw.println(str);
        }
        pw.close();


        System.out.println("已退出,欢迎下次使用");

    }
}

评论

This is just a placeholder img.