IO流(1)-字符流与字节流

news2024/9/29 23:32:38

1. I/O流前置知识

在讲解IO流之前,需要先说明几个小知识点:

(1)bit 是最小的二进制单位,是计算机的操作部分,取值0或1。

(2)Byte(字节)是计算机操作数据的最小单位由 8 位 bit 组成 取值(-128-127)。

(3)Char(字符)是用户的可读写的最小单位,在 Java 里面由 16 位 bit 组成 取值(0- 65535)。

2. I/O流分类

关于io流,有多种分类方式,这里只举最常用的几种。

方式一:按照流的方向进行分类,我们均以内存为参照物。

往内存中去,叫输入流(Input),或者叫做读(Read);

从内存中出来,叫输出流(Ouput),或者叫做写(Write);

如下图所示:

方式二:按照读取数据方式不同进行分类。

1. 有的流按照字节的方式读取数据,一次读取一个字节byte,等同于一次读取8个二进制位。称为字节流。

例如:假设有文件file1.txt

文件内容为 “a中国bc张三” 

第一次读:读取一个字节,读取到‘a’字符(a 字符在windows系统中占用1个字节);

第二次都:读取一个字节,读取到‘中’字符的一半(‘中’汉字字符在windows系统中占用两个字节);

第三次都:读取一个字节,读取到‘中’字符的剩下一半,在显示一半时就会是乱码(‘中’汉字字符在windows系统中占用两个字节);

2. 有的流是按照字符的方式读取数据,一次读取一个字符,,这种流是为了方便读取普通文本文件而存在的,但这种流不能读取:图片,声音,视频,等文件,只能读取纯文本文件,连word文件都无法读取。这种流称为字符流。

例如:假如有文件file1.txt

文件内容为 “a中国bc张三” 

第一次读:读取到‘a’字符(a 字符在windows系统中占用1个字节);

第二次都:读取到‘中’字符(‘中’汉字字符在windows系统中占用两个字节);

3. 有的流是万能流,什么类型的文件都可以读取,包括,文本文件,视频文件,音频文件,图片等。

Java 中IO四大家族,四大家族首领如下:

java.io.InputStream   字节输入流;

java.io.OnputStream   字节输出流;

java.io.Reader   字符输入流;

java.io.Writer   字符输出流;

3. I/O流通用知识点

(1)所有流都实现了java.io.Closeable接口,都是可关闭的,都有Close()方法。

流是一个管道,是内存与硬盘之间的通道,用完之后一定一定要关闭,不然会消耗(占用)更多的资源

(2)所有输出流都实现了java.io.Flushable接口,都是可刷新的,都有flush()方法。所以输出流在最终输出之后,一定要刷新,刷新的作用是为了将管道中的数据全部写入硬盘,清空管道。

如果不刷新,可能会导致数据丢失。

4. Java中常用的IO流方法

Java io包下io流的类有将近40个,这里我列举了常用的16个IO流的类,下面我会挑几个开发中常用的进行用法介绍

文件专属的类

1. java.io.FileInputStream

2. java.io.FileOutputStream

3. java.io.FileReader

4.java.io.FileWriter

转换流(将字节流转换成字符流)

5.  java.io.InputStreamRead 

6. java.io.OnputStreamWriter

缓冲流专属(加快文件读写的效率)

7.java.io.BufferedReader

8.java.io.BufferedWriter

9. java.io.BufferedInputStream

10..java.io.BufferedOnputStream

数据流专属

11. java.io.DataInputStream

12. java.io.DataOnputStream

标准输出流

13. java.io.PrintWriter

14. java.io.PrintStream

对象专属流

15. java.io.ObjectInputStream

16. java.io.ObjectOutputStream

5. FileInputStream 的用法

FileInputStream 是一个字节输入流,它是以字节的方式向内存中读取文件内容

下面是源码中的 FileInputStream ,可以看到,它继承了 InputStream 抽象类

5.1 FileInputStream 的构造方法

FileInputStream 有如上图所示三种构造方法,但常用的是第一种和第三种。

第一个构造方法参数需要传递一个文件的对象

第二种构造方法参数需要传入一个 String 类型的字符串,这里的字符串参数其实指代的是文件的路径,例如我们可以写 "D:\\video"

通常情况下我们会采用第二种构造器,因为直接写文件的路径,在编写时比较直观,第一种还需要去创建一个我们要操作的文件的对象,多此一举,所以我个人更推荐采用第二种方式。

5.2 FileInputStream 的常用方法

如上图所示,因为流都是需要关闭的,所以 close()方法是必须要用到的,通常情况下,一个文件中内容都会很多,所以在三个 read 方法中,read(byte[] b) 和 read(byte[] b ,int off,int len)是比较常用的两个方法;

看我如下代码,我这里各行注释都解释得非常详细

public static void main(String[] args) {
        /**
         *  因为我手动输入的文件路径可能有误,或者程序找不到指定文件,会爆出异常,
         *  又因为这是在 main 方法中,所以采用 try catch 捕获异常
         *  这里使用 try catch 捕获异常还有一个好处,就是可以在 finally 语句块中关闭流
         */
        // 这里提前把 FileInputStream 对象创建为空
        InputStream is = null;
        try {
            // 给FileInputStream 对象赋值
            is = new FileInputStream("D:\\study\\IDEA\\workspaces\\cloud-demo\\user-service\\test.txt");
            
            // 定义一个字节数组,一次读取 5 个字节
            byte[] buffer = new byte[5];
            
            // 定义一个int类型的变量 length 接收 is 读取到的字节数量,
            int length;
            
            // 采用循环的方式读取文件内容,当 length = -1时,说明读取完成,结束循环
            while ((length = is.read(buffer)) != -1){
                // new 一个字符串输出读取到的字节内容,从0索引开始,读取 length 个字节,防止多读少读等情况的发生
                // 这里细节不换行,因为我们要确保读取出来的格式与原文件完全一致
                System.out.print(new String(buffer,0,length));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 这里做一个判空操作,非空才关闭,如果为空还关闭,会出现空指针异常
                if (is != null){
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

这里有一点需要注意,我定义的字节数组大小为5,但实际开发时,我们可以把它定义的很大,或者直接把它定义成要读取的文件的本身大小,这样只读取一次就可以了,减少磁盘IO次数,提高程序的运行效率。

6. FileOnputStream 的用法

FileOutputStream 是一个字节输出流,它是以字节的方式从内存向硬盘写入内容

6.1 FileOutputStream 的构造方法

FileOutputStream 的构造方法如下图所示,这里的 boolean append 是一个可选参数选项,如果在定义时设置为 true ,说明是要在文件末尾追加内容;

如果不设置,默认为false,那么我们在往文件中写入内容的时候,会把原来的内容覆盖。

这个构造器的方法是与 FileInputStream 相似的,参数为 file 是要传入一个文件对象,参数为 String 是要我们传入要操作的文件的路径,这里就不需要我在过多的解释了。

6.2 FileOutputStream 的常用方法

FileOutputStream 与 FileInputStream 的操作方法也和FileInputStream 非常相似,只不过是从读文件变成了写文件,相应方法如下所示

FileOutputStream 输出流可以把内存中的东西写入到磁盘中去长久保存,其实也可以结合 File InputStream 输入流完成文件的复制操作,思路很简单,我们知道,文件是保存在磁盘中的,我们可以先通过输入流将要复制的文件读取到内存中去,然后再通过输出流写入到硬盘中我们制定好的位置,就能完成文件的复制操作。

6.3 FileOutputStream与FileOutputStream结合使用

如下图所示,在我的电脑中C盘下的某个文件夹中,我存放着一个名为 "tupian.png" 屏幕截图,现在要通过IO流的方式将该图片复制到 D盘目录下

具体代码如下所示,我注释的都非常详细,非常好理解,就不需要我做很多的解释了:

public static void main(String[] args) {
        /**
         *  因为我手动输入的文件路径可能有误,或者程序找不到指定文件,会爆出异常,
         *  又因为这是在 main 方法中,所以采用 try catch 捕获异常
         *  这里使用 try catch 捕获异常还有一个好处,就是可以在 finally 语句块中关闭流
         */
        // 这里提前把 FileInputStream 对象创建为空
        InputStream is = null;

        // 这里提前把 FileOutputStream 对象创建为空
        OutputStream os = null;
        try {
            // 给FileInputStream 对象赋值
            is = new FileInputStream("C:\\Users\\18727\\Pictures\\Screenshots\\tupian.png");

            // 给 FileOutputStream 对象赋值
            os = new FileOutputStream("D:\\tupian.png");
            // 定义一个字节数组,一次读取 1024 * 2 个字节,也就是2kb 字节
            byte[] buffer = new byte[1024 * 2];

            // 定义一个int类型的变量 length 接收 is 读取到的字节数量,
            int length;

            // 采用循环的方式读取文件内容,当 length = -1时,说明读取完成,结束循环
            while ((length = is.read(buffer)) != -1){
                // 循环读取文件,并在读取文件的同时输出文件内容
                os.write(buffer,0,length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 这里做一个判空操作,非空才关闭,如果为空还关闭,会出现空指针异常
                // 此外还有一点需要注意,如果创建了多个流,关闭时最好谁最晚创建谁先关闭,顺序不要乱,否则后期可能会出问题
                if (os != null)
                    os.close();
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

然后我们运行上述的 main 方法,得到如下图片中的结果

程序运行完成,这个时候可以发现,在D盘根目录下,已经出现了名为 "tupian.png" 的图片,说明已经被拷贝过来了。

其实我上面所写的程序,可以复制任何文件,如图片,音频,视频,文件夹,文本文件都可以,因为在计算机底层,所有文件都是以字节的方式存储的,而我们所写的方法正是字节输入流与字节输出流。

7. FileReader 的用法

FileReader 是字符输入流,它与 FileInputStream 的区别就是去读取内容的方式不一样,FileReader 是以字符的方式读取数据。我们可以进行类比学习,下面我就简单介绍了, FileReader 的构造方法与读取方法如下图所示

我们还是和刚才一样,写一个 main 方法,读取文件中的内容

public static void main(String[] args) {
        // 这里提前把 FileReader 对象创建为空
        FileReader fr = null;
        //仍然使用 try catch finally 进行异常捕获与流的关闭
        try {
            // 这里使用相对路径读取文件
            fr = new FileReader("user-service/test.txt");

            // 定义一个字符数组 长度为 8
            char[] buffer = new char[8];

            int length;
            while ((length = fr.read(buffer)) != -1){
                // 输出读取到的字符内容
                System.out.print(buffer);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fr != null){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

我们在该项目的目录下新建一个 test.txt 文件,并加入一些字符

 运行 main 方法,可以看到运行成功,文件中的内容已经被打印出来。

8. FileWriter 的用法

FileWriter 是什么,该怎么理解,其实对比着 FileOutputStream 与 FileInputStream 就很好理解了,FileWriter是字节输出流,它可以以自己的方式将内存中的内容写入到硬盘中长久保存。

我们还是用刚才的例子,把 项目中的 test.txt 文件中的内容写入到D盘根本目录下的 test.txt 文件去,代码如下所示

public static void main(String[] args) {
        // 这里提前把 FileReader 对象创建为空
        FileReader fr = null;
        // 这里提前把 FileWriter 对象创建为空
        FileWriter fw = null;
        //仍然使用 try catch finally 进行异常捕获与流的关闭
        try {
            // 这里使用相对路径读取文件
            fr = new FileReader("user-service/test.txt");

            // 对fw 对象赋值,指定D盘下的 test.txt 文件
            fw = new FileWriter("D:/test.txt");

            // 定义一个字符数组 长度为 8
            char[] buffer = new char[8];

            int length;
            while ((length = fr.read(buffer)) != -1){
                // 将读取到的内容写入到 text.txt 文件中
                fw.write(buffer,0,length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (fw != null){
                    fw.close();
                }
                if (fr != null){
                    fr.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

我们运行此方法,得到如下结果,然后在电脑D盘下,可以找到已经存在的 test.txt 文件,这里程序会帮我们自动创建,打开该文件,可以发现内容也都复制过来了

这里我再对字符输出流多一点补充,我们在使用字符输出流之后,一定要进行刷新,其实字符输出流的底层,它会把要写入到硬盘的内容全部都暂存到内存的缓存中去,当要输入的内容全部输出完毕后,缓存区的内容就会一次性的全部加入到硬盘,如果不刷新,它就不会到达硬盘。

由于在 close() 方法中,已经添加了刷新缓存的操作,所以就不需要我们手动刷新了。

但是,一旦我们调用了 close() 方法,那么内存与硬盘的通道就会断开,无法再次输出,如果我们的程序中还会再次使用到字节输出流,建议手动刷新缓存而不关闭缓存,这样下次使用的时候就不需要再次创建流对象了,可以提高程序的效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/808067.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PayPal:全球金融科技领域当之无愧的巨无霸

来源:猛兽财经 作者:猛兽财经 全球最大的金融科技公司之一PayPal(PYPL)将于2023年8月2日发布其2023年第二季度的财报。多年以来该公司一直在革新数字汇款和收款方式,并提高数百万客户的生活质量。此外,PayPal的各种工具也为企业…

Java文件操作与流处理

文章目录 一、文件1.1 文件的概念1.2 文件的组织结构1.3 绝对路径和相对路径 二、文件操作File类2.1 属性和常用方法2.2 使用案例 三、字节流和字符流3.1 InputStream 和 FileInputStream3.2 使用 Scanner 读取字符3.2 OutputStream 和 FileOutputStream3.3 Reader 和 FileRead…

【每日一题】141. 环形链表

【每日一题】141. 环形链表 【每日一题】141. 环形链表题目描述解题思路 【每日一题】141. 环形链表 题目描述 给你一个链表的头节点 head ,判断链表中是否有环。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环…

深入理解C++命名空间

文章目录 1. 命名空间的概念2. 解决命名冲突3. 嵌套命名空间4. 使用命名空间别名总结 在C编程中,命名空间(Namespace)是一种非常有用的工具,它可以帮助我们组织和管理代码,避免命名冲突。本文将深入介绍C命名空间的概念…

WIZnet W5500-EVB-Pico树莓派入门教程(一)

概述 W5500-EVB-Pico是基于树莓派RP2040和完全硬连线TCP/IP控制器W5500的微控制器开发板-基本上与树莓派Pico板相同,但通过W5500芯片增加了以太网功能。 板载资源 RP2040是Raspberry Pi的首款微控制器。它将我们的高性能、低成本和易用性的标志性价值观带入微控制器…

【Android安全】Embedded Trace Microcell模块

ETM: Embedded Trace Macrocell, hardware unit responsible to generate hardware instruction trace. ETM模块用于在硬件层面实现instruction trace,可用于辅助逆向分析。 使用教程: https://mcuoneclipse.com/2016/11/05/tutorial-getting-etm-inst…

如何集成 Milvus 和 LangChain?

以下代码集成了 Milvus 和 LangChain: class VectorStore(ABC):"""Interface for vector stores.""" @abstractmethoddef add_texts(self,texts: Iterable[str],metadatas: Optional[List[dict]] = None, kwargs:Any,) ->List[str]: &…

[STL]详解list模拟实现

[STL]list模拟实现 文章目录 [STL]list模拟实现1. 整体结构总览2. 成员变量解析3. 默认成员函数构造函数1迭代器区间构造函数拷贝构造函数赋值运算符重载析构函数 4. 迭代器及相关函数迭代器整体结构总览迭代器的模拟实现begin函数和end函数begin函数和end函数const版本 5. 数据…

Spring源码(四)— 创建BeanDefinition

在第一章序言的图示中有提到,Spring中的配置文件都是通过各种的BeanDefinition来进行解析,并且支持不同类型的文件进行扩展。所以在创建完DefaultListableBeanFactory后,会通过BeanDefinition来解析传入的xml配置文件。 loadBeanDefinitions…

如何建立ftp server?快解析内网穿透实现外网直接访问

serveru是一款由Rob Beckers开发的获奖的ftp服务器软件,全称为:serv-u ftp server,它功能强大又易于使用。ftp服务器用户通过它用ftp协议能在internet上共享文件。serv-u不仅100%遵从通用ftp标准,也包括众多的独特功能可为每个用户…

常用直线模组的类型

目前,直线模组的应用非常广泛,而且直线模组的种类也有很多可以满足每个行业的应用要求,那么常见的直线模组类型有哪些,大家知道吗? 1、全封闭滚珠丝杆直线模组: 在半封闭式的基础上增加了不锈钢带防尘结构…

自监督去噪: self2self 原理及实现(Pytorch)

Self2Self With Dropout: Learning Self-Supervised Denoising From Single Image 文章地址:https://ieeexplore.ieee.org/document/9157420原始代码:https://github.com/scut-mingqinchen/self2self本文参考代码: https://github.com/JinYize/self2self…

无线系统传输距离(天线收发功率计算)

无线通信系统如图8.1. 发射机发射功率,发射机天线增益; 接收机发射功率,接收机天线增益; 收发之间的距离是R; 如果没有大气损耗,极化失配,阻抗不匹配等情况,且天线在远场区域工作,那么各向同性发射天线在接收天线处的功率密度为 (8.1) 对于定向性天线,该公式修正…

No105.精选前端面试题,享受每天的挑战和学习

文章目录 手写new手写Mapget和post区别发起post请求的时候,服务端是怎么解析你的body的(content-type),常见的content-type都有哪些,发文件是怎么解析的(FormData),如果多个文件&…

微信小程序|进度条

进度条是一个常见的用户界面元素,用于显示任务或操作的完成进度,可以在任何需要指示任务进度的情况下使用,以提供更好的用户体验和反馈。 一、前言1.1 进度条使用场景1.2 进度条属性介绍1.3 示例代码及效果二、自定义进度条2.1 进度条形状2.2 进度条尺寸2.3 进度条条纹2.4 进…

【计算机网络】10、ethtool

文章目录 一、ethtool1.1 常见操作1.1.1 展示设备属性1.1.2 改变网卡属性1.1.2.1 Auto-negotiation1.1.2.2 Speed 1.1.3 展示网卡驱动设置1.1.4 只展示 Auto-negotiation, RX and TX1.1.5 展示统计1.1.7 排除网络故障1.1.8 通过网口的 LED 区分网卡1.1.9 持久化配置&#xff08…

GitHub仓库如何使用

核心:GitHub仓库如何使用 目录 1.创建仓库: 2.克隆仓库到本地: 3.添加、提交和推送更改: 4.分支管理: 5.拉取请求(Pull Requests): 6.合并代码: 7.其他功能&…

windows 10/11 修改右键新建菜单

问题:修改右键新建菜单内容 解决方法:使用软件ShellNew Settings 1.打开软件 2.根据需要取消勾选项 3.最终效果

Linux 系列 常见 快捷键总结

强制停止 Ctrl C 退出程序、退出登录 Ctrl D 等价 exit 查看历史命令 history !命令前缀,自动匹配上一个命令 (历史命令中:从最新——》最老 搜索) ctrl r 输入内去历史命令中检索 # 回车键可以直接执行 ctrl a 跳到命令开头 …

zoho邮箱全收邮件catchall的设置

登录 Zoho Mail 管理控制台。(https://mailadmin.zoho.com/cpanel/home.do#)转到域菜单,然后选择要为其配置“全收邮箱”地址的域。转到设置选项卡,然后找到全收邮箱地址部分。从下拉列表中选择您要配置为“全收邮箱”的电子邮件地址,然后单击…