乐趣区

关于java:Java基础IO字节字符流-读取与写出

IO 简介

in / out 是 绝对于程序而言 的输出(读取) 和输入 (写出) 的过程。
在 Java 中,依据解决的数据单位不同,分为字节流和字符流

继承构造

java.io 包:File
字节流:针对二进制文件
InputStream
    // 想要应用此类的话,则首先必须通过子类实例化对象,那么如果当初要操作的是一个文件,则能够应用:FileInputStream 类。通过向上转型之后,能够为 InputStream 实例化
    FileInputStream
    BufferedInputStream
OutputStream
    // 同上
    FileOutputStream
    BufferedOutputStream

字符流:针对文本文件。读写容易产生乱码景象,在读写时最好指定编码集为 utf-8
Writer
    // 同上
    BufferedWriter
    OutputStreamWriter
Reader
    // 同上
    BufferedReader
    InputStreamReader

流的概念

数据的读写形象成数据,在管道中流动
看图:

需知:
1)流只能单方向流动
2) 输出流用来读取 in
3)输入流用来写出 Out
4)数据只能从头到尾程序的读写一次

字节流读取

字节流是由字节组成的, 字符流是由字符组成的. Java 里字符由两个字节组成. 字节流是最根本的,所有的 InputStream 和 OutputStream 的子类都是,次要用在解决二进制数据

流式传输 次要指将整个音频和视频及三维媒体等多媒体文件 通过特定的压缩形式解析成一个个压缩包,由视频服务器向用户计算机程序或实时传送。在采纳流式传输方式的零碎中,用户不用像采纳下载方式那样等到整个文件全副下载结束,而是只需通过几秒或几十秒的启动延时即可在用户的计算机上利用解压设施对压缩的 A /V、3D 等多媒体文件解压后进行播放和观看。此时多媒体文件的残余局部将在后盾的服务器内持续下载。

InputStream 抽象类

此抽象类是示意 字节输出流 的所有类的超类 / 抽象类
罕用办法:

abstract int read()
    从输出流中读取数据的下一个字节。int read(byte[] b)
    从输出流中读取肯定数量的字节,并将其存储在缓冲区数组 b 中。int read(byte[] b, int off, int len)
    将输出流中最多 len 个数据字节读入 byte 数组。void close()
    敞开此输出流并开释与该流关联的所有系统资源。
FileInputStream 子类

构造方法:

FileInputStream(File file)
    通过关上一个到理论文件的连贯来创立一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。FileInputStream(String pathname)
    通过关上一个到理论文件的连贯来创立一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。
BufferedInputStream 子类

BufferedInputStream 为另一个输出流增加一些性能,即缓冲输出以及反对 mark 和 reset 办法的能力。在创立 BufferedInputStream 时,会创立一个外部缓冲区数组(默认 8KB 大小 ==8192)。在读取或跳过流中的字节时,可依据须要从蕴含的输出流再次填充该外部缓冲区,一次填充多个字节

构造方法:

BufferedInputStream(InputStream in)
    创立一个 BufferedInputStream 并保留其参数,即输出流 in,以便未来应用。

字节流写出

OutputStream 抽象类

此抽象类是示意 输入字节流 的所有类的超类。输入流承受输入字节并将这些字节发送到某个接收器。

罕用办法:

void close()
    敞开此输入流并开释与此流无关的所有系统资源。void flush()
    刷新此输入流并强制写出所有缓冲的输入字节。void write(byte[] b)
    将 b.length 个字节从指定的 byte 数组写入此输入流。void write(byte[] b, int off, int len)
    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输入流。abstract void write(int b)
    将指定的字节写入此输入流。
FileOutputStream 子类

构造方法:

FileOutputStream(String name)
    创立一个向具备指定名称的文件中写入数据的输入文件流。FileOutputStream(File file)
    创立一个向指定 File 对象示意的文件中写入数据的文件输入流。FileOutputStream(File file, boolean append) –追加
    创立一个向指定 File 对象示意的文件中写入数据的文件输入流
BufferedOutputStream 子类

该类实现缓冲的输入流。通过设置这种输入流,应用程序就能够将各个字节写入底层输入流中,而不用针对每次字节写入调用底层零碎。
构造方法:

BufferedOutputStream(OutputStream out)
     创立一个新的缓冲输入流,以将数据写入指定的底层输入流。

字节流读写

代码:

package com.cy.pj.common.io;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class ByteStreamReadAndWriteTests {public static void main(String[] args) {FIS();
        BIS();
        FOS();
        BOS();}

    private static void FIS() {
        InputStream in = null;
        try {in = new FileInputStream( "E:\\testForIO\\testForIOin.txt");
            long start = System.currentTimeMillis();
            while (( in.read() ) != -1 ) { }
            long end = System.currentTimeMillis();
            System.out.println("曾经没有数据了! FileInputStream 读取用时"+(end-start)+"ms!" );
        } catch (IOException e) {e.printStackTrace();
        } finally {
            try {in.close();
            } catch (IOException e) {e.printStackTrace();
            }
        }
    }

    private static void BIS() {
        InputStream in = null;
        try {in = new BufferedInputStream( new FileInputStream( "E:\\testForIO\\testForIOin.txt") );
            long start = System.currentTimeMillis();
            while (( in.read() ) != -1 ) { }
            long end = System.currentTimeMillis();
            System.out.println("曾经没有数据了! BufferedInputStream 读取用时"+(end-start)+"ms!" );
        } catch (IOException e) {e.printStackTrace();
        } finally {
            try {in.close();
            } catch (IOException e) {e.printStackTrace();
            }
        }
    }

    private static void FOS() {
        OutputStream out = null;
        try {out = new FileOutputStream( "E:\\testForIO\\testForIOout.txt");
            long start = System.currentTimeMillis();
            for (int i = 0; i < 10000; i++) {out.write( i);
            }
            long end = System.currentTimeMillis();
            System.out.println("写出实现! FileOutputStream 写出用时"+(end-start)+"ms!" );
        } catch (IOException e) {e.printStackTrace();
        } finally {
            try {out.close();
            } catch (IOException e) {e.printStackTrace();
            }
        }
    }

    private static void BOS() {
        OutputStream out = null;
        try {out = new BufferedOutputStream( new FileOutputStream( "E:\\testForIO\\testForIOout.txt") );
            long start = System.currentTimeMillis();
            for (int i = 0; i < 10000; i++) {out.write( i);
            }
            long end = System.currentTimeMillis();
            System.out.println("写出实现! BufferedOutputStream 写出用时"+(end-start)+"ms!" );
        } catch (IOException e) {e.printStackTrace();
        } finally {
            try {out.close();
            } catch (IOException e) {e.printStackTrace();
            }
        }
    }

}

运行后果:

曾经没有数据了! FileInputStream 读取用时 378 ms!
曾经没有数据了! BufferedInputStream 读取用时 3 ms!
写出实现! FileOutputStream 写出用时 41 ms!
写出实现! BufferedOutputStream 写出用时 1 ms!

能够看出无论读取还是写出 Buffered 都要比 File 快上几十倍不止。Buffered 底层保护着一个数组,能够了解为:运货,Buffered 是辆大货车,先装满箱再登程,而 File 就是一个一个登程
看图:



字符流读取

罕用于解决纯文本数据。

Reader 抽象类

用于 读取字符流 的抽象类
罕用办法:

int read()
    读取单个字符
int read(char[] cbuf)
    将字符读入数组。abstract int read(char[] cbuf, int off, int len)
    将字符读入数组的某一部分。int read(CharBuffer target)
    试图将字符读入指定的字符缓冲区。abstract void close()
    敞开该流并开释与之关联的所有资源。
FileReader 子类

用来读取字符文件的便捷类。此类的构造方法假设默认字符编码和默认字节缓冲区大小都是适当的。要本人指定这些值,能够先在 FileInputStream 上结构一个 InputStreamReader。

构造方法:

FileReader(String fileName)
    在给定从中读取数据的文件名的状况下创立一个新 FileReader。FileReader(File file)
    在给定从中读取数据的 File 的状况下创立一个新 FileReader。
InputStreamReader 子类

InputStreamReader 是 字节流通向字符流 的桥梁:它应用指定的 charset 读取字节并将其解码为字符。它应用的字符集能够由名称指定或显式给定,或者能够承受平台默认的字符集。

构造方法:

InputStreamReader(InputStream in, String charsetName)
    创立应用指定字符集的 InputStreamReader。InputStreamReader(InputStream in)
    创立一个应用默认字符集的 InputStreamReader。
BufferedReader 子类

从字符输出流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
能够指定缓冲区的大小,或者可应用默认的大小。大多数状况下,默认值就足够大了。

构造方法:

BufferedReader(Reader in)
    创立一个应用默认大小输出缓冲区的缓冲字符输出流。

字符流写出

Writer 抽象类

写入字符流 的抽象类
罕用办法:

void write(char[] cbuf)
    写入字符数组。abstract void write(char[] cbuf, int off, int len)
    写入字符数组的某一部分。void write(int c)
    写入单个字符。void write(String str)
    写入字符串。void write(String str, int off, int len)
    写入字符串的某一部分。abstract void close()
    敞开此流,但要先刷新它。
FileWriter 子类

用来写入字符文件的便捷类。此类的构造方法假设默认字符编码和默认字节缓冲区大小都是可承受的。要本人指定这些值,能够先在 FileOutputStream 上结构一个 OutputStreamWriter。

构造方法:

FileWriter(String fileName)
    依据给定的文件名结构一个 FileWriter 对象。FileWriter(String fileName, boolean append)
    依据给定的文件名以及批示是否附加写入数据的 boolean 值来结构 FileWriter 对象。
OutputStreamWriter 子类

OutputStreamWriter 是 字符流通向字节流 的桥梁:可应用指定的 charset 将要写入流中的字符编码成字节。它应用的字符集能够由名称指定或显式给定,否则将承受平台默认的字符集。

构造方法:

OutputStreamWriter(OutputStream out, String charsetName)
    创立应用指定字符集的 OutputStreamWriter。OutputStreamWriter(OutputStream out)
    创立应用默认字符编码的 OutputStreamWriter。
BufferedWriter 子类

将文本写入字符输入流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。能够指定缓冲区的大小,或者承受默认的大小。在大多数状况下,默认值就足够大了。

构造方法:

BufferedWriter(Writer out)
    创立一个应用默认大小输入缓冲区的缓冲字符输入流。

字符流读写

把数据写出到指定文件中。如果文件不存在会主动创立,文件夹不存在会报错。
代码:

package com.cy.pj.outputstream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

public class ReaderAndWriter {public static void main(String[] args) throws Exception {ISR();
        BR();
        OSW();
        BW();}

    private static void ISR() {System.out.println( "代码是一样的 这里不再写 InputStreamReader 间接写 BufferedReader");
    }

    private static void BR() {
        BufferedReader in = null;
        try {in = new BufferedReader( new InputStreamReader( new FileInputStream( "G:\\testForIO\\testForIORead.txt") ) );
            long start = System.currentTimeMillis();
            in.readLine();
            long end = System.currentTimeMillis();
            System.out.println("曾经没有数据了! BufferedReader 读取用时"+(end-start)+"ms!" );
        } catch (IOException e) {e.printStackTrace();
        } finally {
            try {in.close();
            } catch (IOException e) {e.printStackTrace();
            }
        }
    }

    private static void OSW() {System.out.println( "代码是一样的 这里不再写 OutputStreamWriter 间接写 BufferedWriter");
    }

    private static void BW() {
        BufferedWriter out = null;
        try {
            // 留神设置编码格局 避免乱码
            out = new BufferedWriter(new OutputStreamWriter( new FileOutputStream( "G:\\testForIO\\testForIOWrite.txt"),"utf-8" ) );
            long start = System.currentTimeMillis();
            for (int i = 0; i < 100; i++) {out.write( "榴莲");
            }
            long end = System.currentTimeMillis();
            System.out.println("写出实现! BufferedWriter 写出用时"+(end-start)+"ms!" );
        } catch (IOException e) {e.printStackTrace();
        } finally {
            try {
                // 开释资源
                out.close();} catch (IOException e) {e.printStackTrace();
            }
        }
    }
}

运行后果:

代码是一样的 这里不再写 InputStreamReader 间接写 BufferedReader
曾经没有数据了! BufferedReader 读取用时 57 ms!
代码是一样的 这里不再写 OutputStreamWriter 间接写 BufferedWriter
写出实现! BufferedWriter 写出用时 0 ms!

其余:

1) 在写入时默认为笼罩原有内容,应尽量避免这种操作,能够应用后面构造方法的追加构造方法进行追加写入,防止数据的删除
2) FileNotFoundException 异样为零碎找不到该文件,能够查看下门路进行排查
3) NullPointerException 异样为空指针异样,可能跟门路无关,也有可能是因为某个变量值为 null
4) IO 属于资源操作, 记得敞开流
5) 文件中换行为:r n
6) InputStream 读取到空数据返回 -1 Reader 为 null
7) 字节流在操作的时候自身是不会用到缓冲区(内存)的,是与文件自身间接操作的,而字符流在操作的时候是应用到缓冲区的
8) 字节流在操作文件时,即便不敞开资源(close 办法),文件也能输入,然而如果字符流不应用 close 办法的话,则不会输入任何内容,阐明字符流用的是缓冲区,并且能够应用 flush 办法强制进行刷新缓冲区,这时能力在不 close 的状况下输入内容
9) 字节用的多

退出移动版