u05-流类处理

228 阅读5分钟

1. 缓冲流

概念: 缓冲流自带一个缓冲区,可以让传输过程更加高效和流畅,且缓冲流附带一些其他功能方法。

1.1 BufferedInputStream

概念: 缓冲字节输入流BufferedInputStream是InputStream的一个子类。

  • 构造器:
    • BufferedInputStream(InputStream in)
    • BufferedInputStream(InputStream in, int size)
    • size 是缓冲区默认大小,默认为8192b,即8K。
  • 常用API方法:
    • int read():从此输入流中读取一个字节的数据,如果文件已经读完,返回-1。
    • void mark(int readlimit):标记的位置,只取决于该方法被调用时,bis指针的位置,跟参数无关。
      • p1:一个以字节为单位的标记有效期。
    • void reset():回到上一个标记的位置,如果当前 mark() 过期,则报错。

mark() 的有效期不仅仅取决于它的参数,还取决于 BufferedInputStream() 的缓存,这两个值,谁大谁生效,如 mark() 有效期为4个字节,BufferedInputStream() 的缓存是8192个字节,所以最终只要读的字节数量没超过8192,都可以成功 reset()

源码: /javase-advanced/

  • src: c.y.io.BufferedSeriesTest.bufferedInputStream()
/**
 * @author yap
 */
public class BufferedSeriesTest {

    private String filePath = "D:" + File.separator + "java-io" + File.separator + "HelloWorld.java";

    /**
     * 对 `HelloWorld.java` 文件进行中间部分内容读取12-3456-3456
     */
    @Test
    public void bufferedInputStream() {
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath), 5)) {
            System.out.println("pos-01:" + (char) bis.read());
            System.out.println("pos-02:" + (char) bis.read());
            bis.mark(4);
            System.out.println("pos-03:" + (char) bis.read());
            System.out.println("pos-04:" + (char) bis.read());
            System.out.println("pos-05:" + (char) bis.read());
            System.out.println("pos-06:" + (char) bis.read());
            System.out.println("pos-06:" + (char) bis.read());
            bis.reset();
            System.out.println("pos-03:" + (char) bis.read());
            System.out.println("pos-04:" + (char) bis.read());
            System.out.println("pos-05:" + (char) bis.read());
            System.out.println("pos-06:" + (char) bis.read());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

多个IO流嵌套的时候,程序最后只需要关闭最外层的IO流即可。

2.2 BufferedOutputStream

概念: 缓冲字节输出流BufferedOutputStream是OutputStream的一个子类。

  • 构造器:
    • BufferedOutputStream(OutputStream out)
    • BufferedOutputStream(OutputStream out, int size)
    • size 是缓冲区默认大小,默认为8192b,即8K。
  • 常用API方法:
    • void write(int b):将指定的字节b写入此文件输出流。
    • void flush():刷新此输出流并强制任何缓冲的输出字节被写出来。

源码: /javase-advanced/

  • src: c.y.io.BufferedSeriesTest.bufferedOutputStream()
/**
 * @author yap
 */
public class BufferedSeriesTest {

    private String filePath = "D:" + File.separator + "java-io" + File.separator + "HelloWorld.java";

    /**
     * 对一个文件写入10个A
     */
    @Test
    public void bufferedOutputStream() {
        String destPath = "D:" + File.separator + "java-io" + File.separator + "io.txt";
        try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destPath))) {
            int times = 10;
            for (int i = 0; i < times; i++) {
                bos.write('B');
            }
            System.out.println("write over...");
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.3 BufferedReader

概念: 缓冲字符输入流BufferedReader是Reader的一个子类。

  • 构造器:
    • BufferedReader(Reader in)
    • BufferedReader(Reader in, int size)
    • size 是缓冲区默认大小,默认为8192b,即8K。
  • 常用API方法:
    • int read():从此输入流中读取一个字节的数据,如果文件已经读完,返回-1。
    • String readLine():从此输入流中读取一行数据,如果文件已经读完,返回null。
    • skip()mark()reset() 都支持。

源码: /javase-advanced/

  • src: c.y.io.BufferedSeriesTest.bufferedReader()
/**
 * @author yap
 */
public class BufferedSeriesTest {

    private String filePath = "D:" + File.separator + "java-io" + File.separator + "HelloWorld.java";

    /**
     * 一行一行地读取 `HelloWorld.java` 文件,并打印在控制台上
     */
    @Test
    public void bufferedReader() {
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String str;
            while ((str = br.readLine()) != null) {
                System.out.println(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.4 BufferedWriter

概念: 缓冲字符输出流BufferedWriter是Writer的一个子类。

  • 构造器:
    • BufferedWriter(Writer out)
    • BufferedWriter(Writer out, int size)
    • size 是缓冲区默认大小,默认为8192b,即8K。
  • 常用API方法:
    • void write(String b):将指定的字符串写入此文件输出流。
    • void newLine():插入一个换行符。
    • void flush():刷新此输出流并强制任何缓冲的输出字节被写出来。

源码: /javase-advanced/

  • src: c.y.io.BufferedSeriesTest.bufferedWriter()
/**
 * @author yap
 */
public class BufferedSeriesTest {

    private String filePath = "D:" + File.separator + "java-io" + File.separator + "HelloWorld.java";

    /**
     * 向指定文件写入100个随机数,每个随机数占据一行
     */
    @Test
    public void bufferedWriter() {
        String filePath = "D:" + File.separator + "java-io" + File.separator + "random.txt";
        try (BufferedWriter bw = new BufferedWriter(new FileWriter(filePath))) {
            Random random = new Random();
            for (int i = 0, j = 100; i < j; i++) {
                bw.write("随机数:" + (random.nextInt(100)));
                bw.newLine();
            }
            System.out.println("write over...");
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. 转换流

概念: 我们可以利用处理转换流将字节流转换成对应的字符流。

2.1 InputStreamReader

概念: 字节输入转换流InputStreamReader是Reader的一个子类。

  • 构造器:
    • InputStreamReader(InputStream in)
    • InputStreamReader(InputStream in, String charset)
    • InputStreamReader(InputStream in, Charset cs)
    • charset 是字符编码字符串,默认UTF8,建议使用 StandardCharsets.UTF_8
  • 常用API方法:
    • int read():从此输入流中读取一个字节的数据,如果文件已经读完,返回-1。
    • String getEncoding():获取当前流中的字符集。

源码: /javase-advanced/

  • src: c.y.io.TransformSeriesTest.inputStreamReader()
/**
 * @author yap
 */
public class TransformSeriesTest {

    private static void inputStreamReader() {
        // System.in is typeof InputStream
        try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) {
            String str;
            while ((str = br.readLine()) != null) {
                if ("exit".equals(str)) {
                    break;
                }
                System.out.println(">> " + str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 设计模拟Scanner读取控制台信息的方法,要求输入 `exit` 时可以退出。
     * IDEA中的Junit和System.in或者Scanner有冲突,需要换成main方法测试
     */
    public static void main(String[] args) {
        inputStreamReader();
    }
}

3.2 OutputStreamWriter

概念: 字节输出转换流OutputStreamWriter是Writer的一个子类。

  • 构造器:
    • OutputStreamWriter(OutputStream out)
    • OutputStreamReader(OutputStream out, String charset)
    • OutputStreamReader(OutputStream out, Charset charset)
    • charset 是字符编码字符串,默认UTF8,建议使用 StandardCharsets.UTF_8
  • 常用API方法:
    • void write(String str):将指定的字符串写入此文件输出流。
    • void flush():刷新此输出流并强制任何缓冲的输出字节被写出来。

源码: /javase-advanced/

  • src: c.y.io.TransformSeriesTest.outputStreamWriter()
/**
 * @author yap
 */
public class TransformSeriesTest {
    /**
     * 向文件中写入一个UTF8的 "你好" 和一个 GBK的 "世界"
     */
    @Test
    public void outputStreamWriter() {
        String destPath = "D:" + File.separator + "java-io" + File.separator + "hello.txt";
        OutputStreamWriter osw = null;
        try {
            FileOutputStream fos = new FileOutputStream(destPath);
            osw = new OutputStreamWriter(fos, "UTF-8");
            osw.write("你好");
            System.out.println(osw.getEncoding());
            osw.flush();
            osw = new OutputStreamWriter(fos, "GBK");
            osw.write("世界");
            System.out.println(osw.getEncoding());
            osw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (osw != null) {
                try {
                    osw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

4. 打印流

概念: 打印流是输出语句的底层结构,无需抛出IO异常,且自带flush效果。

4.1 PrintStream

概念: 打印字节流PrintStream是OutputStream的一个子类。

  • 构造器:
    • PrintStream(OutputStream out)
    • PrintStream(OutputStream out, boolean autoFlush)
    • PrintStream(OutputStream out, boolean autoFlush, String charset)
    • PrintStream(String fileName)
    • PrintStream(String fileName, String charset)
    • PrintStream(File file)
    • PrintStream(File file, String charset)
    • charset是字符编码字符串,默认UTF8。
    • autoFlush 是PrintWriter的刷新属性:
      • 为true时,每次写入,打印,或读到换行符等操作的时候都会flush。
      • 为false时,只flush一次(默认)。
  • 常用API方法
    • void print(String str):不换行打印,底层封装的write()。
    • void println():换行打印,底层封装的write()。
    • void printf():格式化打印,底层封装的write()。
  • System类的一个API方法:
    • void setOut(PrintStream out):重新定义输出语句中的out的位置(默认指向控制台)。
    • void setErr(PrintStream err):重新定义输出语句中的err的位置(默认指向控制台)。

源码: /javase-advanced/

  • src: c.y.io.PrintSeriesTest.printStream()
/**
 * @author yap
 */
public class PrintSeriesTest {

    /**
     * 重新定义打印语句的目标位置为硬盘文件,并打印Unicode前128个字符,并还原
     */
    @Test
    public void printStream() {
        String destPath = "D:" + File.separator + "java-io" + File.separator + "ps.dat";
        try (PrintStream ps = new PrintStream(new FileOutputStream(destPath), true)) {
            PrintStream defaultOut = System.out;
            System.setOut(ps);
            int max = 128;
            for (int i = 0; i < max; i++) {
                System.out.print((char) i + " ");
            }
            System.setOut(defaultOut);
            System.out.println("print over...");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

如果修改out指定之后,需要恢复原来的指向(控制台),则需要在setOut()之前,对System.out进行备份,然后在后面的某个位置调用setOut()来还原备份。

4.2 PrintWriter

概念: 打印字符流PrintWriter是Writer的一个子类。

  • 构造器:
    • PrintWriter(OutputStream out)
    • PrintWriter(OutputStream out, boolean autoFlush)
    • PrintWriter(Writer out)
    • PrintWriter(Writer out, boolean autoFlush)
    • PrintWriter(String fileName)
    • PrintWriter(String fileName, String charset)
    • PrintWriter(File file)
    • PrintWriter(File file, String charset)
    • charset是字符编码字符串,默认UTF8。
    • autoFlush 是PrintWriter的刷新属性:
      • 为true时,每次写入,打印,或读到换行符等操作的时候都会flush。
      • 为false时,只flush一次(默认)。
  • 常用API方法:
    • void print(String str):不换行打印,底层封装的write()。
    • void println():换行打印,底层封装的write()。
    • void printf():格式化打印,底层封装的write()。
  • System类的一个API方法:
    • void setOut(PrintStream out):重新定义输出语句中的out的位置(默认指向控制台)。
    • void setErr(PrintStream err):重新定义输出语句中的err的位置(默认指向控制台)。

源码: /javase-advanced/

  • src: c.y.io.PrintSeriesTest.printWriter()
/**
 * @author yap
 */
public class PrintSeriesTest {

    /**
     * 设计一个模拟Log4j(java的日志文件)工作的方法
     */
    @Test
    public void printWriter() {
        String destPath = "D:" + File.separator + "java-io" + File.separator + "my-log.log";
        try (PrintWriter pw = new PrintWriter(new FileWriter(destPath, true), true)) {
            String msg01 = "添加了一个用户";
            String msg02 = "修改了一个用户";
            String msg03 = "删除了一个用户";
            pw.println(msg01);
            pw.println(msg02);
            pw.println(msg02);
            pw.println("LOGGING AT " + new Date());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}