Java 基础: IO流 -- 字节流和字符流的区别和使用,分别实现文本的复制(详细)

   日期:2020-05-24     浏览:93    评论:0    
核心提示:前置知识: File 类的基本使用与了解。流:在介绍 IO 流之前先来说下什么是流: 流是一种 FIFO 的数据结构(类似于队列,先进先出)。简单来说,就像水流一样。输入流和输出流:输入流和输出流是相对于 内存 这个参照物来说的。流的划分:上图中很多类都是抽象类,所以都需要通过其子类进行实现。(父类引用指向子类对象 – 多态)注意:1、字节流:字节流就是将内容转为了字节形式进行传输, 1 字节 有 8 个二进制位组成,在底层,文件都是有二进制组成的,所以二进制可以传输任何类型的数据,进java

前置知识: File 类的基本使用与了解。

流:

在介绍 IO 流之前先来说下什么是流: 流是一种 FIFO 的数据结构(类似于队列,先进先出)。简单来说,就像水流一样。

输入流和输出流:

输入流和输出流是相对于 内存 这个参照物来说的。

流的划分:


上图中很多类都是抽象类,所以都需要通过其子类进行实现。
(父类引用指向子类对象 – 多态)
注意:
1、字节流:字节流就是将内容转为了字节形式进行传输, 1 字节 有 8 个二进制位组成,在底层,文件都是有二进制组成的,所以二进制可以传输任何类型的数据,进而 字节流也可以传输任何类型的数据。
2、字节流是 8 位通用字节流(可以处理任意类型,处理文本以外的其他文件)
3、字符流是 16 位 unicode 字符流(只用于处理字符,处理文本文件)
4、字符流:一般只用来处理字符,当我们传输图片的时候,转码的时候容易出现乱码,字节流也可以处理字符相关的文本,但是效率没有字符流更好。

输入流实现文本的读取:

在流到内存的时候因为我们不知道文件的具体大小,也就是字节数组的大小开多少比较合适
我们是不知道的,所以需要通过 in.available() 方法得到文件的大小,进而实现流动。

package io;

import java.io.*;

public class Demo03 {

    public static void main(String[] args) throws IOException {
        // 提高作用域,便于关闭
        InputStream in = null;
        try{
            // InputStream 是一个抽象类,需要通过子类进行实现
            in = new FileInputStream(new File("hello.txt"));

            // 得到文件的总大小
            System.out.println(in.available());
            // 先将文件放到缓冲区里面,这里的缓冲区是一个 字节数组
            byte[] buf = new byte[in.available()];

            // 流到内存中
            in.read(buf);

            // 输出一下
            System.out.println(new String(buf));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 防止出现空指针
            if(in != null) in.close();
        }
    }
}

hello.txt 文本中的内容:

输出结果;

输出流实现将内容输出到文件中:

package io;

import java.io.*;

public class Demo04 {

    public static void main(String[] args) throws IOException {
        OutputStream out = null;
        try {
            // 与 输入流类似
            out = new FileOutputStream(new File("d.txt"));
            // 通过子节的方式将 hello123 读取到 d.txt 文件中
            out.write("hello123".getBytes());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
           if(out != null) out.close();
        }

    }

}

d.txt

字节流实现文件的复制:

在实现文件的复制时,需要注意以下几点:
1、由于文件可能很大,可能有几个G,但是我们不可能一次开辟那么大的空间,所以可以分块进行流动,每次开辟一定的空间。
2、分块流动时可能会有多出来的一部分: 比如 135 byte,我们规定每次最多只能传输 10 byte,但是 最后会 只剩下 5 byte 还没有传输,这个时候缓冲区里面存储的还是上一次的 10byte,而新来的 5byte 只会替换前 5 个:如下图:
原文件:

复制后的文件:

可以清晰的看到,复制后的文件与原文件中的内容出现不一致,这个问题该怎么处理呢?
详见代码:


3、一定要记得关闭 输入流和输出流,否则会出现文件内容读不进去的尴尬!

package io;

import java.io.*;

public class Demo05 {


    public static void main(String[] args) {

        InputStream in = null;
        OutputStream out = null;

        try{
            // 将原文件读到内存区
            in = new FileInputStream(new File("a.txt"));
            // 从 内存区 输出到 要复制的地方
            out = new FileOutputStream(new File("b.txt"));

            // 缓存区(每次都流动 10 byte)
            byte[] buf = new byte[10];
            int len = -1;
            // in.read(buf) 返回值是流动到 内存区的 长度
            while((len = in.read(buf) )!= -1) {
                // 每次都流动的是 实际 的长度(这样可以避免出现文件不一致的情况)
                out.write(buf,0,len);
            }

        }catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 一定要记得关 流
                if(out != null) out.close();
                if(in != null) in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }

}

字符流实现文件的复制:

实现功能:

将a.txt文件中的内容 复制到 b.txt 文件中,并且将占位符替换掉。

package io;

import java.io.*;

public class Demo06 {

    public static void main(String[] args) {
        Reader in = null;
        Writer out = null;
        try {

            // 字符输入流
            in = new FileReader(new File("a.txt"));
            // 字符输出流
            out = new FileWriter(new File("b.txt"));
            // 字节流是 字节数组作为缓冲区,字符流是 字符数组作为缓冲区
            char[] buf = new char[4];
            // 拼接字符串,由于 Sting 每次拼接时都要在 常量池中开辟新的空间,效率较低,所以我们选择用 StringBuffer
            StringBuffer sb = new  StringBuffer();

            int len = -1;

            while((len = in.read(buf)) != -1) {
                sb.append(buf,0,len);
            }

            System.out.println(sb);

            // 转换为 String 类型,替换相应的内容
            String content = sb.toString();
            content = content.replace("name","潘小蓝")
                      .replace("age","22")
                      .replace("address","HN");
            // 输出到 相应文件中
            out.write(content);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            try {
               if(in != null) in.close();
               if(out != null) out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }


    }

}

效果图:

后记:

如果各位看官有疑问的或者有哪里解释的不清楚的,欢迎提出,在下会细心改正,大家共同进步,加油!!!

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服