当前位置: 首页 > article >正文

Java -- IO流

IO流

主要用于读写数据

IO流按照流的方向可以分为以下两种:

  1. 输入流
  2. 输出流

IO流按照操作文件类型可以分为以下两种:

  1. 字节流
  2. 字符流

字节流可以操作所有类型的文件,而字符流只可以操作纯文本文件

IO流体系
字节流
InputStream
OutputStream
字符流
Writer
Reader

下面四个都是抽象类,具体使用要使用他的子类。

FileOutputStream

操作本地文件的字节输出流,可以把程序中的数据写到本地文件中。

下面是一个小示例:

    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("inarray.txt");
        fos.write(97);
        fos.close();
    }

文件写入的步骤有三个

  1. 创建字节输出流对象

参数是字符串表示的路径或者File对象

如果文件不存在会创建一个新文件,但是要保证父级路径是存在的,也就是不可以创建文件夹

如果文件已经存在,会清空文件

  1. 写数据

write方法的参数是整数,但是实际是写的对应的ascii值

参数也可以是字节数组

  1. 释放资源

解除资源的占用

write方法的三种重载

方法作用
void write(int b)一次写一个字节数据
void write(byte[] b)一次写一个字节数组数据
void write(byte[] b,int off, int len)一次写一个字节数组的部分数据

后两种的方法演示:

        FileOutputStream fos = new FileOutputStream("inarray.txt");
        fos.write("Hello world!".getBytes());
        fos.close();
        FileOutputStream fos = new FileOutputStream("inarray.txt");
        byte[] bytes = "Hello world!".getBytes();
        fos.write(bytes, 5, bytes.length - 5);
        fos.close();

换行写和续写

换行写可以添加一个换行符的ascii值

在字符串中添加一个换行符即可,但是不同操作系统的换行符是不一样的:

在windows操作系统中,回车换行是\r\n

在linux操作系统中,是\n

在mac操作系统中,是\r

在windows操作系统中,java对回车换行进行了优化,我们使用\r或者\n均可以实现回车换行效果,java会自动给我们补齐,但是在书写的过程中还是要完整书写,养成良好的习惯。

        FileOutputStream fos = new FileOutputStream("inarray.txt");
        byte[] bytes = "Hello world!".getBytes();
        fos.write(bytes, 5, bytes.length - 5);
        fos.write("\n666".getBytes());
        fos.close();

构造方法其实有两个参数,第二个参数是续写开关,设置第二个参数为true就不会把原来的内容清空了

        FileOutputStream fos = new FileOutputStream("inarray.txt", true);
        byte[] bytes = "Hello world!".getBytes();
        fos.write(bytes, 5, bytes.length - 5);
        fos.write("\n666".getBytes());
        fos.close();

FileInputStream

下面是读取一个字节的示例:

        FileInputStream fis = new FileInputStream("inarray.txt");
        System.out.println(fis.read());
        fis.close();

read方法会一个字节一个字节的读取文件,如果读取不到了返回值-1

下面是一个循环读取字符的例子:

        FileInputStream fis = new FileInputStream("inarray.txt");
        int b = fis.read();
        while (b != -1) {
            System.out.println((char) b);
            b = fis.read();
        }
        fis.close();

文件读取也有三个步骤:

  1. 创建字节输入流对象
  • 如果文件不存在直接报错
  1. 读取数据
  • 每次读取的是一个字节,并且返回的是ASCII值
  • 读取到末尾read会返回-1
  1. 释放资源

每次使用完流必须释放资源

循环读取

        FileInputStream fis = new FileInputStream("inarray.txt");
        int b;
        while ((b = fis.read()) != -1) {
            System.out.println((char) b);
        }
        fis.close();

这是对于while循环的一种简便的写法

文件拷贝

拷贝一个小文件的例子:

        FileInputStream fis = new FileInputStream("C:\\Users\\nanming\\Desktop\\汇编语言实验报告打印\\1.pdf");
        FileOutputStream fos = new FileOutputStream("to.pdf");
        int b;
        while ((b = fis.read()) != -1)
            fos.write(b);
        fos.close();
        fis.close();

运行会发现,程序运行的时间会比较长

如果文件比较大,速度则会非常的慢

这时候就要用read的重载方法:

方法作用
public int read()读取一个字节
public int read(byte[] buffer)一次读取一个字节数组

理论上数组越大,读取速度也就越快,但是实际上数组如果过大,内存会直接崩溃,通常申请一个1024整数倍大小的数组,比如说1024*1024*5即5M的数组

        FileInputStream fis = new FileInputStream("C:\\Users\\nanming\\Desktop\\汇编语言实验报告打印\\1.pdf");
        FileOutputStream fos = new FileOutputStream("to.pdf");
        byte b[] = new byte[1024 * 1024 * 5];
        while (fis.read(b) != -1)
            fos.write(b);
        fos.close();
        fis.close();

将字节数组转换为字符串可以使用String类型的构造方法

上面的方法会有一个弊端:

        FileInputStream fis = new FileInputStream("raf.txt");
        FileOutputStream fos = new FileOutputStream("inarray.txt");
        byte b[] = new byte[5];
        while (fis.read(b) != -1)
            fos.write(b);
        fos.close();
        fis.close();

当读取到最后一次时,没有将数组读满,但是写入的时候写入的还是整个数组,也就是包含了上一次读出的数据,数据重叠了

下面是对于文件拷贝的改写:

        FileInputStream fis = new FileInputStream("raf.txt");
        FileOutputStream fos = new FileOutputStream("inarray.txt");
        byte b[] = new byte[5];
        int len;
        while ((len = fis.read(b)) != -1)
            fos.write(b, 0, len);
        fos.close();
        fis.close();

在使用try catch捕获异常时,如果还要照顾close时的异常,那么还要再嵌套一层的try catch,这样的话就会显得非常复杂,JAVA设计了特殊的方法可以自动关闭资源,按照下面两种方式书写均可

try(创建流1;创建流2){
    可能出现异常的代码;
}catch(异常类名 变量名){
    异常处理;
}
创建流对象1;
创建流对象2;
try(1;2){
    可能出现异常的代码;
}catch(异常类名 变量名){
    异常处理;
}

而如果不自动关闭则需要按照下面的方式书写:

try{
    可能出现异常的代码;
}catch(异常类名 变量名){
    异常处理;
}finally{
    执行所有资源释放操作;//这里还要嵌套try catch块
}

但是自动释放是有前提的,需要流实现了接口AutoCloseable

编码规则

GBK编码规则:

GBK兼容ASCII码

  1. 汉字以两个字节存储
  2. 高位字节二进制一定以1开头(为了与ASCII表区分开)

unicode码中有一个utf-8规格,其中:

(unicode是一个字符集,utf-8是对于unicode的编码规则)

ASCII码:1个字节

简体中文:3个字节

乱码出现的原因

  1. 读取时没有读完

因为一个汉字由三个字节存储,使用字节流读取时,按照一个字节一个字节的读取,每次读取的字节在表中查不到对应的数据就会显示?方框

  1. 编码和解码规则不相同

比如说一个汉字按照Unicode编码,占用了三个字节,而解码时按照GBK格式解码,前两个字节解释为一个汉字,最后一个字节找不到对应的编码,就会显示黑三角问号

为了预防乱码的出现

  1. 不要以字节流读取文件
  2. 要保证编码解码方式一致

Java中的编码解码方式

方法作用
public byte[] getBytes()使用默认方式进行编码
public byte[] getBytes(String charsetName)使用指定方式进行编码
String(byte[] bytes)使用默认方式进行解码
String(byte[] bytes[],String charsetName)使用指定方式进行解码

字符流

字符流的底层还是字节流,但是他更加的高级:

  1. 输入流中,会一次读取一个字节,当遇到中文的时候一次读取多个字节
  2. 输出流中,也会把数据按照指定的编码形式进行编码,变为字节再写到文件中去

适用于纯文本文件

FileReader

  1. 创建字符输入流对象
方法作用
public FileReader(File file)创建字符输入流关联本地文件
public FileReader(String pathname)创建字符输入流

如果文件不存在直接报错

  1. 读取数据
方法作用
public int read()读取数据,都到末尾返回-1
public int read(char[]buffer)读取多个数据,都到末尾返回-1

按照字节进行读取,如果遇到中文,一次读取多个字节,读取后解码返回一个整数

  1. 释放资源
public int close();//关流
        FileReader fis = new FileReader("inarray.txt");
        char b[] = new char[5];
        int len;
        while ((len = fis.read(b)) != -1)
            System.out.print(new String(b, 0, len));
        fis.close();

FileWriter

方法作用
public FileWriter(File file)创建字符输出流
public FileWriter(String pathName)创建字符输出流
public FileWriter(File file,boolean append)是否续写
public FileWriter(String PathName,boolean append)是否续写
方法作用
void write(int c)写一个字符
参数作用
String str写一个字符串
String str, int off, int len写一个字符串的一部分
char[] cbuf写一个字符数组
char[] cbuf, int off, int len写出字符数组的一部分

根据当前字符集进行编码把编码之后的数据写入对应文件中去

内存中有一个8K的缓冲区,读取的时候先放到缓冲区,再按照要求读取,读完了再把文件中的内容放到缓冲区,每次都尽可能填满缓冲区

写入的时候也是先写入缓冲区,当缓冲区满或者手动刷新或者关闭资源时写入文件

方法作用
public void flush()刷新缓冲区,将缓冲区数据放到文件中,刷新后可以继续向文件中写入数据
public void close()关闭通道,关闭后无法再写出数据;释放资源

http://www.kler.cn/a/14779.html

相关文章:

  • 【AI】Python 脚本转换为可执行文件 EXE
  • 04_并发容器类
  • Linux进程通信:无名管道
  • 低代码开发重要工具:jvs-logic(逻辑引擎)能力扩展及代码集成
  • 经常打电话的人用什么耳机好?通话质量好的蓝牙耳机推荐
  • Doris(16):物化视图
  • IU5180C升降压充电芯片特点及应用
  • 【LeetCode】987.二叉树的垂序遍历
  • chatGPT电脑端怎么安装-chatgpt国内怎么用
  • 【LeetCode】剑指 Offer 67. 把字符串转换成整数 p318 -- Java Version
  • 指定GPU运行python程序
  • 若[x]补 =1,x1x2x3x4x5x6,其中x取0或1,若要x>-32,应当满足
  • 4月24日作业
  • Hadoop 生态圈及核心组件简介Hadoop|MapRedece|Yarn
  • #cordova添加plugin的方法#
  • day-01 one-day projects
  • sd卡中病毒的表现及sd文件消失后的恢复方法
  • 23年校赛
  • 【Mybatis代码生成器Mybatis-Generator】
  • JavaScript每日五题面试题(第六天)