4.4 字节流-字节缓冲流-过渡知识(字符集)-IO流(字符流)

IO流是什么?

一句话:IO流就是程序中数据的管道,可以做数据传输

举例一:

指挥Java程序读取文件中的数据,还可以将数据写出到文件(上传\下载)(学习到网络编程后,就可以实现了)

举例二:

服务端用Java程序读取客户端发送的消息,再回写数据

客户端用Java程序读取服务端发送的消息,再回写数据

画图理解

yuque_diagram

IO流的分类

流向分为:

  • 输入流 \ input(读取)
  • 输出流 \ output(写出)

类型分为:

字节流:可以操作任意类型文件,因为文件存储的时候就是字节,但是操作纯文本文件的时候,有可能会乱码

一个识别小技巧:用windows系统的记事本打开,如果不是乱码,就是纯文本文件,如果是乱码,就不是纯文本文件

字符流:只能操作纯文本文件,解决字节流读取文件的乱码问题

IO流的体系结构

iotixi

识别流的思路

流对象以Stream为结尾,肯定是字节流

流对象以Reader \ Writer 为结尾的,肯定是字符流

字节流和字符流的使用场景

  • 如果操作的是纯文本文件,优先使用字符流
  • 如果操作的是图片、视频、音频等二进制文件,优先使用字节流
  • 如果不确定文件类型,优先使用字节流,字节流是万能的流

IO流程序书写流程

  1. 在操作之前,要导包,java.io包
  2. 在操作流对象的时候,要处理解决异常(IOException)
  3. 在操作完流对象之后,必须关闭资源, 所有流资源的关闭 close( );

字节流写出数据

作用

可以将字节数据写出到指定的文件中

FileOutputStream类

构造方法和描述:

FileOutputStream(File file)创建文件输出流以写入由指定的File对象表示的文件

FileOutputStream(File file, boolean append)创建文件输出流以写入由指定的File对象表示的文件

FileOutputStream(FileDescriptor fdObj)创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接

FileOutputStream(String name)创建文件输出流以指定的名称写入文件

FileOutputStream(String name, boolean append)创建文件输出流以指定的名称写入文件,第二个参数为true,表示追加写入的数据

所有方法:

返回值类型

方法和描述

void

close()关闭此文件输出流并释放与此流相关联的任何系统资源

protected void

finalize()清理与文件的连接,并确保当没有更多的引用此流时,将调用此文件输出流的close方法

FileChannel

getChannel()返回与此文件输出流相关联的唯一的FileChannel对象

FileDescriptor

getFD()返回与此流相关联的文件描述符

void

write(byte[] b)b.length个字节从指定的字节数组写入此文件输出流

void

write(byte[] b, int off, int len)将字节数组的一部分写到文件中,b代表字节数组,off代表开始索引,len代表个数

void

write(int b)将指定的字节写入此文件输出流

字节流常见的两个问题

换行:

  • Windows:\r\n 举例:输出流对象.write("需要写入的数据\r\n".getBytes());
  • Mac:\r
  • Linux:\n

追加:

  • FileOutputStream(String name, boolean append):第二个参数为true,表示追加写入的数据
  • 注意:如果构造方法没有打开追加写入的开关,执行构造方法会把文件中内容清空

案例小练习

需求:键盘录入用户输入的消息,将接收到的消息保存在当前模块下 info.txt,直到用户输入 886 结束程序

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class StreamTest1 {
    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
        FileOutputStream fos = new FileOutputStream("day11-code\\info.txt", true);

        while (true) {
            System.out.println("请输入您要输入的数据:");
            String msg = sc.nextLine();
            if ("886".equals(msg)) {
                fos.close();
                break;
            }
            fos.write(msg.getBytes());
            fos.write("\r\n".getBytes());
        }
    }
}

IO流异常处理-标准的关流代码

IO流异常处理代码(JDK7标准):

被finally修饰的程序,一定会执行

public static void main(String[] args) {
	FileOutputStream fos = null;
    try {
    	fos = new FileOutputStream("day11-code\\c.txt");
        fos.write("你好".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (fos != null) {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

IO流异常处理代码(JDK8标准):

try (需要关流的对象) {
	IO流的逻辑代码
} catch (异常类 对象名) {
	异常的处理方案
}

只需要将关流的对象,放在try()中,就会自动关流了
细节:try()中的对象,需要实现AutoCloseable接口
public static void main(String[] args) {
    try (FileOutputStream fos = new FileOutputStream("day11-code\\c.txt");) {
        fos.write("你好".getBytes());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

字节流读取数据

作用:

可以将文件中的字节数据读取出来

FileInputStream类:

构造方法和描述

FileInputStream(File file)通过打开与实际文件的连接创建一个FileInputStream,该文件由文件系统中的File对象file命名

FileInputStream(FileDescriptor fdObj)创建FileInputStream通过使用文件描述符fdObj,其表示在文件系统中的现有连接到一个实际的文件

FileInputStream(String name)通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名

所有方法

返回值类型

方法和描述

int

read()一次读取一个字节的数据,如果读取到了文件末尾,将会返回-1

int

read(byte[] b)从该输入流读取最多b.length个字节的数据为字节数组,方法返回的是:读取到的有效字节个数

int

read(byte[] b, int off, int len)从该输入流读取最多len字节的数据为字节数组

long

skip(long n)跳过并从输入流中丢弃n字节的数据

int

available()返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞

void

close()关闭此文件输入流并释放与流相关联的任何系统资源

protected void

finalize()确保当这个文件输入流的close方法没有更多的引用时被调用

FileChannel

getChannel()返回与此文件输入流相关联的唯一的FileChannel对象

FileDescriptor

getFD()返回表示与此FileInputStream正在使用的文件系统中实际文件的连接的FileDescriptor对象

读取方式:

一次读取一个数据

public static void main(String[] args) throws IOException {
    // 创建字节输入流对象
    FileInputStream fis = new FileInputStream(new File("day11-code\\a.txt"));
    // 循环的读取, 一次读取一个字节
    int i;
    while ((i = fis.read()) != -1) {
        System.out.println((char) i);
    }
    // 关流释放资源
    fis.close();
}

一次读取一个字节数组

public static void main(String[] args) throws IOException {
    // 创建字节输入流对象
    FileInputStream fis = new FileInputStream("day11-code\\a.txt");
    byte[] bys = new byte[2];
    int len;
    // 循环的读取, 一次读取一个字节
    while ((len = fis.read(bys)) != -1) {
        String s = new String(bys, 0, len);
        System.out.print(s);
    }
    // 关流释放资源
    fis.close();
}

案例 : 字节流拷贝文件

需求:使用字节流实现文件拷贝

分析:

  1. 创建输入流关联要拷贝的文件
  2. 创建输出流关联数据目的
  3. 读写操作
  4. 关闭流释放资源(要求实现自动关流)
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyTest1 {
    public static void main(String[] args) {
        // 1.创建输入流关联要拷贝的文件
        // 2.创建输出流关联数据目的
        try (FileInputStream fis = new FileInputStream("D:\\a.flv");
             FileOutputStream fos = new FileOutputStream("E:\\a.flv");) {
            // 3.读取操作
            int i;
            byte[] bys = new byte[1024];
            while ((i = fis.read(bys)) != -1) {
                fos.write(bys, 0, i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字节缓冲流

介绍:提高读写效率

字节缓冲流构造方法

输入:public BufferedInputStream(InputStream in):创建一个缓冲输入流对象,参数是基本的字节输入流

输出:public BufferedOutputStream(OutputStream out):创建一个缓冲输出流对象,参数是基本的字节输出流

注意:缓冲流不具备读写功能,只提供缓冲区,读写操作,还是需要依赖于基本的流

代码演示

public class BufferedStreamDemo {
    public static void main(String[] args) throws IOException {
        // 创建字节缓冲输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day11-code\\a.txt"))

        // 创建字节缓冲输出流
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStram("day11-code\\copy.txt"))

        byte[] bys = new byte[1024];
        int len;
        while ((len = bis.read(bys)) != -1) {
            bos.write(bys, 0, len);
        }

        bis.close();
        bos.close();
    }
}

四种文件流的拷贝方式

普通字节流(单个字节拷贝):每次读写一个字节,效率很差

image

普通字节流 + 自定义数组拷贝(314M 耗时 : 2404毫秒,数组设置为 8192个大小后 314M 耗时 : 436 毫秒)

image

缓冲流(单个字节拷贝)(314M 耗时 : 8407毫秒)

image

缓冲流 + 自定义数组拷贝(314M 耗时 : 406毫秒)

image

过渡知识-字符集

字符集

字符集:说的就是编码表

编码表:计算机中,字符到字节的一套对应关系

ASCII 码表

image

思考 : 字节再往下是什么 ?

二进制

所以, 计算机存储任何数据, 都是以二进制的形式进行存储

需要记住的结论

我们在文件中存储的字符, 实际上都有一份数值的表示形式 !

常见的编码表 :

ASCII : 所有码表都囊括了 ASCII 码表

GBK : 中国的码表, 每个中文, 占用2个字节

Unicode – UTF-8:万国码, 每个中文, 占用3个字节

编码-解码

概念介绍 :

编码 : 将看得懂的, 变成看不懂的 (字符转字节)

解码 : 将看不懂的, 变成看得懂的 (字节转字符)

编码 :

image

解码 :

image

字符串类 String 的编码解码 :

image

图解

image

需要重点记住的 :

如果今后出现了乱码 : 查看编码和解码的方式是否一致

  • GBK : 每个中文占用2个字节
  • UTF-8 : 每个中文占用3个字节
  • 英文, 数字, 标点符号, 都占用1个字节

中文的字节表示形式, 第一个肯定是负数

IO流-字符流

字符流应用

如果操作的文件是纯文本文件,想要避免中文乱码问题,就可以使用字符流

字符流组成

字节流 + 编码表

image

字符流方法

读数据方法:

public int read():一次读取一个字符

public int read(char[] cbuf):一次读取一个字符数组

分类 :

FileReader(字符输入流) :

构造方法:

public FileReader(String fileName):据给定的文件名构造一个FileReader对象

概述 : 用来读取字符文件的便捷类

FileWriter(字符输出流):

使用FileWriter写出数据:字符输出流,如果写出数据后,没有调用close方法,数据将无法写入文件

解决方案:

close():主要的职责是关闭流释放资源,只不过关闭之前,顺手将缓冲区的数据,刷出到文件中

flush():专门刷出数据的方法

区别:close方法关闭流之后,不能继续写出数据了

构造方法:

public FileWriter(String fileName):使用字符输出流对象关联文件,文件路径以字符串形式给出

public FileWriter(File file):使用字符输出流对象关联文件,文件路径以File对象形式给出

© 版权声明
THE END
喜欢就支持一下吧
点赞337赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容