Java基础 - Java核心类库 - IO 流

Java基础 - Java核心类库 - IO 流

1 IO 流

1.1 基本概念
  • I (input)输入,O(output)输出
1.2 基本分类

(1)按照读写数据的基本单位不同分类:

  • 字节流
    • 字节流主要指以字节为单位进行数据读写的流,可以读写任意类型的文件
  • 字符流
    • 字符流主要指以字符(2个字节)为单位进行数据读写的流,只能读写文本文件

(2)按照读写数据方向不同分类:

  • 输入流
    • 输入流主要指从文件中读取数据内容输入到程序中,也就是读文件
  • 输出流
    • 输出流主要指将程序中的数据内容输出到文件中,也就是写文件

(3)按照流的角色不同进行分类:

  • 节点流
    • 节点流主要指直接和输入输出源对接的流
  • 处理流
    • 处理流主要指需要建立在节点流的基础之上的流
1.3 体系结构

1.4 FileWriter 类
1.4.1 基本概念
  • java.io.FileWriter类主要用于将文本内容写入到文本文件
1.4.2 常用方法
(1)FileWriter(String fileName) 根据参数指定的文件名构造对象,若文件不存在该流会自动创建新空文件,若文件存在该流会清空文件中的原有内容
(2)FileWriter(String fileName, boolean append) 以追加的方式根据参数指定的文件名来构造对象,不想清除存在文件原有内容设置为true
(3)void write(int c) 写入单个字符,可以直接'a'表示
(4)void write(char[] cbuf, int off, int len) 将指定字符数组中从偏移量off开始的len个字符写入此文件输出流
(5)void write(char[] cbuf) 将cbuf.length个字符从指定字符数组写入此文件输出流中
(6)void flush() 刷新流
(7)void close() 关闭流对象并释放有关的资源,先flush刷新再关闭
1.5 FileReader 类
1.5.1 基本概念
  • java.io.FileReader类主要用于从文本文件读取文本数据内容
1.5.2 常用方法
FileReader(String fileName) 根据参数指定的文件名构造对象
int read() 读取单个字符的数据并返回,返回-1表示读取到末尾,可以通过(char) int强转得到字符
int read(char[] cbuf, int offset, int length) 从输入流中将最多len个字符的数据读入一个字符数组中(从cbuf的offset下标写入),返回读取到的字符个数,返回-1表示读取到末尾
int read(char[] cbuf) 从此输入流中将最多 cbuf.length 个字符的数据读入字符数组中,返回读取到的字符个数,返回-1表示读取到末尾
void close() 关闭流对象并释放有关的资源
1.6 FileOutputStream类
1.6.1 概念
  • java.io.FileOutputStream类主要用于将图像数据之类的原始字节流写入到输出流中
1.6.2 常用方法
FileOutputStream(String name) 根据参数指定的文件名来构造对象
FileOutputStream(String name,boolean append) 以追加的方式根据参数指定的文件名来构造对象
void write(int b) 将指定字节写入此文件输出流
void write(byte[] b, int off, int len) 将指定字节数组中从偏移量off开始的len个字节写入此文件输出流
void write(byte[] b) 将 b.length 个字节从指定字节数组写入此文件输出流中
void flush() 刷新此输出流并强制写出任何缓冲的输出字节
void close() 关闭流对象并释放有关的资源
1.7 FileInputStream 类
1.7.1 基本概念
  • java.io.FileInputStream类主要用于从输入流中以字节流的方式读取图像数据等
1.7.2 常用方法
FileInputStream(String name) 根据参数指定的文件路径名来构造对象
int read() 从输入流中读取单个字节的数据并返回,返回-1表示读取到末尾
int read(byte[] b, int off, int len) 从此输入流中将最多len个字节的数据读入字节数组中,返回读取到的字节个数,返回-1表示读取到末尾
int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入字节数组中,返回读取到的字节个数,返回-1表示读取到末尾
void close() 关闭流对象并释放有关的资源
int available() 获取输入流所关联文件的大小
1.8 BufferedOutputStream
1.8.1 基本概念
  • java.io.BufferedOutputStream类主要用于描述缓冲输出流,此时不用为写入的每个字节调用底层系统
1.8.2 常用方法
BufferedOutputStream(OutputStream out) 根据参数指定的引用来构造对象,默认缓存大小为8192
BufferedOutputStream(OutputStream out, int size)根据参数指定的引用和缓冲区大小来构造对象
void write(int b) 写入单个字节
void write(byte[] b, int off, int len) 写入字节数组中的一部分数据
void write(byte[] b) 写入参数指定的整个字节数组
void flush() 刷新流
void close() 关闭流对象并释放有关的资源
1.9 BufferedInputStream
1.9.1 基本概念
  • java.io.BufferedInputStream类主要用于描述缓冲输入流
1.9.2 常用方法
BufferedInputStream(InputStream in) 根据参数指定的引用构造对象
BufferedInputStream(InputStream in, int size) 根据参数指定的引用和缓冲区大小构造对象
int read() 读取单个字节
int read(byte[] b, int off, int len) 读取len个字节
int read(byte[] b) 读取b.length个字节
void close() 关闭流对象并释放有关的资源
1.10 文件拷贝
1.10.1 文件字符流实现文件拷贝
//只能拷贝文本文件,.read()方法每次调用都会读取一个字符并向后移动,所以需要一个变量来接收读取到的每个数据

FileReader reader = null;
        FileWriter writer = null;
        try {
            reader = new FileReader("d:/iotest/a.txt");
            writer = new FileWriter("d:/iotest/b.txt");
            int i = 0;
            while ((i=reader.read())!=-1){
                writer.write(i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != reader)
                reader.close();
                if (null != writer)
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
1.10.2 文件字节流实现文件拷贝

(1)单个字节流进行拷贝

//拷贝图片只能使用字节流
//缺点:单个字节为单位进行拷贝,每读取一个字节后再写入一个字节,文件稍大时效率比很低

FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream("d:/iotest/joker.jpg");
            outputStream = new FileOutputStream("d:/iotest/joker2.jpg");

            int i = 0;
            while ((i = inputStream.read()) != -1){
                outputStream.write(i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != inputStream)
                inputStream.close();
                if (null != outputStream)
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

(2)准备一个和文件大小一样的数组一次性拷贝

// 通过available方法获取拷贝文件的长度,再新建一个长度足够的数组来接收文件,接着将文件读入该数组,并判断是否一致,一致的化执行写入操作
//缺点:若文件过大时,无法申请同样大小的内存,真实物理内存不足

FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream("d:/iotest/Leecode.mp4");
            outputStream = new FileOutputStream("d:/iotest/Leecode1.mp4");

            int in = inputStream.available();
            byte[] arr = new byte[in];

            int read = inputStream.read(arr);

            if (read == in) outputStream.write(arr);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != inputStream)
                inputStream.close();
                if (null != outputStream)
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

(3)准备大小合理的数组分批次进行拷贝

//一般根据需要拷贝的文件的大小来设置合理的数组大小(为1024的倍数)
//在进行写数据操作时需要调用write(arr,index,len),因为文件可能不是正好为设定的倍数

FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        try {
            inputStream = new FileInputStream("d:/iotest/Leecode.mp4");
            outputStream = new FileOutputStream("d:/iotest/Leecode1.mp4");

            byte[] arr = new byte[1024];

            int i = 0;
            while ((i=inputStream.read(arr)) != -1){
                outputStream.write(arr,0,i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != inputStream)
                inputStream.close();
                if (null != outputStream)
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
1.10.3 缓冲流进行文件拷贝
//新建Buffered实例时需要传入InputStream或OutputStream的子类,如FileInputStream
//在往缓存里写数据时也可以自定义数组批量操作进一步加快效率
//关闭流时关闭外层流内层也会关闭

BufferedInputStream inputStream = null;
        BufferedOutputStream outputStream = null;
        try {
            inputStream = new BufferedInputStream(new FileInputStream("d:/iotest/Leecode.mp4"));
            outputStream = new BufferedOutputStream(new FileOutputStream("d:/iotest/Leecode3.mp4"));

            byte[] arr = new byte[1024];
            int res = 0;
            while ((res = inputStream.read(arr)) != -1){
                outputStream.write(arr,0,res);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(inputStream != null)
                inputStream.close();
                if (outputStream != null)
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
1.11 BufferedWriter 类
1.11.1 基本概念
  • java.io.BufferedWriter类主要用于写入单个字符、字符数组以及字符串到输出流中
1.11.2 常用方法
BufferedWriter(Writer out) 根据参数指定的引用来构造对象
BufferedWriter(Writer out, int sz) 根据参数指定的引用和缓冲区大小来构造对象
void write(int c) 写入单个字符到输出流中
void write(char[] cbuf, int off, int len) 将字符数组cbuf中从下标off开始的len个字符写入输出流中
void write(char[] cbuf) 将字符串数组cbuf中所有内容写入输出流中
void write(String s, int off, int len) 将参数s中下标从off开始的len个字符写入输出流中
void write(String str) 将参数指定的字符串内容写入输出流中
void newLine() 用于写入行分隔符到输出流中,使用/r/n acs 13 10
void flush() 刷新流
void close() 关闭流对象并释放有关的资源
1.12 BufferedReader 类
1.12.1 基本概念
  • java.io.BufferedReader类用于从输入流中读取单个字符、字符数组以及字符串
1.12.2 常用方法
BufferedReader(Reader in) 根据参数指定的引用来构造对象
BufferedReader(Reader in, int sz) 根据参数指定的引用和缓冲区大小来构造对象
int read() 从输入流读取单个字符,读取到末尾则返回-1,否则返回实际读取到的字符内容
int read(char[] cbuf, int off, int len) 从输入流中读取len个字符放入数组cbuf中下标从off开始的位置上,若读取到末尾则返回-1,否则返回实际读取到的字符个数
int read(char[] cbuf) 从输入流中读满整个数组cbuf
String readLine() 读取一行字符串并返回,返回null表示读取到末尾
void close() 关闭流对象并释放有关的资源
1.13 PrintStream 类
1.13.1 基本概念
  • java.io.PrintStream类主要用于更加方便地打印各种数据内容
  • System.out 的打印方法就是使用该类向控制台进行打印
1.13.2 常用方法
PrintStream(OutputStream out) 根据参数指定的引用来构造对象
void print(String s) 用于将参数指定的字符串内容打印出来
void println(String x) 用于打印字符串后并终止该行
void flush() 刷新流
void close() 用于关闭输出流并释放有关的资源
1.14 PrintWriter 类
1.14.1 基本概念
  • java.io.PrintWriter类主要用于将对象的格式化形式打印到文本输出流
1.14.2 常用方法
PrintWriter(Writer out) 根据参数指定的引用来构造对象
void print(String s) 将参数指定的字符串内容打印出来
void println(String x) 打印字符串后并终止该行
void flush() 刷新流
void close() 关闭流对象并释放有关的资源
1.15 OutputStreamWriter 类
1.15.1 基本概念
  • java.io.OutputStreamWriter类主要用于实现从字符流到字节流的转换
1.15.2 常用方法
OutputStreamWriter(OutputStream out) 根据参数指定的引用来构造对象
OutputStreamWriter(OutputStream out, String charsetName)根据参数指定的引用和编码构造对象
void write(String str) 将参数指定的字符串写入
void flush() 刷新流
void close() 用于关闭输出流并释放有关的资源
1.16 InputStreamReader类
1.16.1 基本概念
  • java.io.InputStreamReader类主要用于实现从字节流到字符流的转换
1.16.2 常用方法
InputStreamReader(InputStream in) 根据参数指定的引用来构造对象
InputStreamReader(InputStream in, String charsetName) 根据参数指定的引用和编码来构造对象
int read(char[] cbuf) 读取字符数据到参数指定的数组
void close() 用于关闭输出流并释放有关的资源
1.17 实现聊天并将内容保存到文件中
//使用BufferedReader类来读取键盘的输入 System.in代表键盘输入
//System.in 是InputStream,要使用Reader来接收需要使用InputStreamReader来转换,BufferedReader 的readLine 方法可以读取输入的一行内容
//使用PrintStream类负责将数据写入文件
//PrintStream(OutputStream) 可以使用print方法将内容写入指定文件

BufferedReader reader = null;
        PrintStream stream = null;       
        try {
            reader = new BufferedReader(new InputStreamReader(System.in));
            stream = new PrintStream(new FileOutputStream("d:/iotest/c.txt"));
            while (true){
                System.out.println("请输入聊天内容:");
                String line = reader.readLine();
                System.out.println(line);
                if (line.equals("bye")){
                    break;
                }
                stream.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null)
                    reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
1.18 DataOutputStream类
1.18.1 概念
  • java.io.DataOutputStream类主要用于以适当的方式将基本数据类型写入输出流中
1.18.2 常用方法
DataOutputStream(OutputStream out) 根据参数指定的引用构造对象 OutputStream类是个抽象类,实参需要传递子类对象
void writeInt(int v) 用于将参数指定的整数一次性写入输出流,优先写入高字节 //不同方法可以写入所有基本数据类型
void close() 用于关闭文件输出流并释放有关的资源
  • writeInt 示例
int num = 66;
DataOutputStream.writeInt(num)
最后写入文档中的结果为   B //B前面有三个空白位置
因为默认优先写入高位,66 为int4个字节,0000 0000 ... 0100 0010
0000 0000 对应空白字符
1.19 DataInputStream类
1.19.1 概念
  • java.io.DataInputStream类主要用于从输入流中读取基本数据类型的数据
1.19.2 常用方法
DataInputStream(InputStream in)根据参数指定的引用来构造对象 InputStream类是抽象类,实参需要传递子类对象
int readInt() 用于从输入流中一次性读取一个整数数据并返回
void close() 用于关闭文件输出流并释放有关的资源

//write 和 read 方法需要匹配,write/read 写读一个字节,writeInt/readInt 写读四个字节
1.20 ObjectInputStream类
1.20.1 概念
  • java.io.ObjectInputStream类主要用于从输入流中一次性将对象整体读取出来
  • 所谓反序列化主要指将有效组织的字节序列恢复为一个对象及相关信息的转化过程
1.20.2 常用方法
ObjectInputStream(InputStream in) 根据参数指定的引用来构造对象
Object readObject() 主要用于从输入流中读取一个对象并返回 无法通过返回值来判断是否读取到文件的末尾
void close() 用于关闭输入流并释放有关的资源
1.20.3 序列化版本号

序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时, JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如 果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常 (InvalidCastException)

1.20.4 transient关键字

transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行 化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进 去的

1.20.5 如何写入多个对象

当希望将多个对象写入文件时,通常建议将多个对象放入一个集合中,然后将集合这个整体看做一 个对象写入输出流中,此时只需要调用一次readObject方法就可以将整个集合的数据读取出来, 从而避免了通过返回值进行是否达到文件末尾的判断

1.21 ObjectOutputStream类
1.21.1 概念
  • java.io.ObjectOutputStream类主要用于将一个对象的所有内容整体写入到输出流中
  • 只能将支持 java.io.Serializable 接口的对象写入流中
  • 类通过实现 java.io.Serializable 接口以启用其序列化功能
  • 所谓序列化主要指将一个对象需要存储的相关信息有效组织成字节序列的转化过程
1.21.2 常用方法
ObjectOutputStream(OutputStream out) 根据参数指定的引用来构造对象
void writeObject(Object obj) 用于将参数指定的对象整体写入到输出流中
void close() 用于关闭输出流并释放有关的资源
1.22 RandomAccessFile类
1.22.1 概念
  • java.io.RandomAccessFile类主要支持对随机访问文件的读写操作,以前读取都是顺序读取的,现在可以指定位值
1.22.2 常用方法
RandomAccessFile(String name, String mode) 根据参数指定的名称和模式构造对象
r: 以只读方式打开
rw:打开以便读取和写入
rwd:打开以便读取和写入,同步文件内容的更新
rws:打开以便读取和写入,同步文件内容和元数据的更新
int read() 读取单个字节的数据
void seek(long pos) 用于设置从此文件的开头开始测量的文件指针偏移量
void write(int b) 将参数指定的单个字节写入
void close() 用于关闭流并释放有关的资源
  • seek 传入偏移的位值,传入n,读取第n个位置(假设第一个下标为0)
  • read / writer 操作后会顺序后移
  • seek 指定位值后再写入数据,会覆盖先前的数据

2 字符编码

2.1 编码表

计算机只能识别二进制数据,早期就是电信号。为了方便计算机可以识别各个国家的文字,就需要 将各个国家的文字采用数字编号的方式进行描述并建立对应的关系表,该表就叫做编码表

2.2 常见的编码表
ASCII:美国标准信息交换码, 使用一个字节的低7位二位进制进行表示
ISO8859-1:拉丁码表,欧洲码表,使用一个字节的8位二进制进行表示
GB2312:中国的中文编码表,最多使用两个字节16位二进制为进行表示
GBK:中国的中文编码表升级,融合了更多的中文文字符号,最多使用两个字节16位二进制位表示
Unicode:国际标准码,融合了目前人类使用的所有字符,为每个字符分配唯一的字符码。所有的文字都用两个字节16位二进制位来表示
2.3 编码发展

面向传输的众多 UTF(UCS Transfer Format)标准出现了,UTF-8就是每次8个位传输数据,而 UTF-16就是每次16个位。这是为传输而设计的编码并使编码无国界,这样就可以显示全世界上所 有文化的字符了

Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体 存储成什么样的字节流,取决于字符编码方案。推荐的Unicode编码是UTF-8和UTF-16

UTF-8:变长的编码方式,可用1-4个字节来表示一个字符

posted @ 2020-12-30 13:34  Pengc931482  阅读(134)  评论(0)    收藏  举报