文件IO之 File 类和 InputStream, OutputStream 的用法(二)

简介: 文件IO之 File 类和 InputStream, OutputStream 的用法

文件内容的读写


针对文本文件, 提供了一组类, 统称为 “字符流”, 典型代表 : Reader, Writer. (读写的基本单位是字符)

针对二进制文件, 提供了一组类, 统称为 “字节流”, 典型代表 : InputStream, OutputStream (读写的基本单位是字节)


所谓的 “流”, 就相当于水流, 打开水龙头有水流出来, 就可以通过水流来接水.

同样的如果我们不用了, 也要给它关闭上, 不然会造成资源的浪费.


每种流对象又分为两种 :

输入流 : Reader, InputStream

输出流 : Writer, OutputStream

(注: 这里输入输出, 针对的是CPU来讨论的, 输出就是从硬盘输出到内存, 输入就是从内存写入硬盘)


InputStream 的使用


b4a73f402d7c4568bbb70c9cb620d3a1.png

可以看到, InputStream 是个抽象类, 不能直接实例化, 要使用还需要具体的实现类.

因为 InputStream 是进行 IO 访问的类, 而 IO 不仅仅是读写硬盘的文件, 在网络编程里还可以用来读写网卡.

所以 InputStream 的实现类有很多,基本可以认为不同的输入设备都可以对应一个 InputStream 类,因为我们现在只关心从文件中读取,所以使用 FileInputStream.

513b3d642e524198b4d8c2daa4ef28bc.png


InputStream inputStream = new FileInputStream("test.txt");


意思是 : 打开 hello.txt 文件, 让变量 inputStream 能够和硬盘上的此文件关联起来, 就像有了遥控器, 以后我们要对该文件进行操作, 就可以通过该变量, 间接操作了.

当然, 如果该文件不存在, 就会抛异常 : FileNotFoundException


注意 :


当我们不需要对这个文件操作时, 就要把这个文件进行关闭, 就像打开水流接水, 不用了也得关.


关闭文件用到了 close 方法.


inputStream.close();


补充 :


为啥不关就会造成为文件资源泄漏呢 ?

这里的资源主要就是指 : 文件描述符表, 它是进程的一个结构.

进程的结构是使用 PCB 来表示的.

包括了 : 1.pid, 2.内存指针, 3.文件描述符表

文件描述符表就是记载了当前进程都打开了哪些文件, 每打开一个文件, 就会在表里申请一个位置.

这个表就可以当成一个数组, 数组下标就是文件描述符, 数组元素就是这个文件在内核中的结构体表

示.

遗憾的是, 这个表长度有限, 不能无休止的打开且不释放, 一旦满了 就会打开失败. 这就是文件资源泄漏.


public static void main(String[] args) throws IOException {
        InputStream inputStream = new FileInputStream("d:/test.txt");
        //...代码
        inputStream.close();
    }


其实在中间代码执行过程中, 还可能出现问题, 比如中间就 return 了, 这样同样会导致文件资源泄漏.

我们可以利用 try :


public static void main(String[] args) throws IOException {
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream("d:/test.txt");
        }finally {
            inputStream.close();  //这里的代码一定会被执行到
        }
    }


上述代码还可以进行优化, 变得更简洁 :


public static void main(String[] args) throws IOException {
        try(InputStream inputStream = new FileInputStream("d:/test.txt")) {           
        }
    }


这个操作叫 : try with resources, 也就是带有资源的 try 操作, 资源会在 try 代码块结束时, 自动执行 close 操作.


为啥它能写进 try 里面呢?

其实 InputStream 实现一个特定接口 : Closeable, 实现了该接口的类, 就可以写成这种语法.


读操作


5368d17fef7e4f688ea5000df3849ce2.png

以 read 来说明 : 从输入流读取数据的下一个字节。 读到的字节被作为 int 返回, 因为是字节, 所以范围就是 0~255 。 如果没有读到字节,可能已经到达流的末尾,则返回值-1 .


现在我们来读取数据, 首先在 d 盘创建个文件 :

ca3e8a999d8d41c89ea2f80983d32a37.png


public class Test {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream = new FileInputStream("d:/test.txt")) {
            while(true) {
                int a = inputStream.read();  //为什么不用byte接收, 就是因为它的表示范围是 0 ~ 255,不能表示-1
                if(a == -1) {   //读到末尾结束循环
                    break;
                }
                System.out.printf("%d\n", a);  //以十进制打印每个字符
            }
        }
    }
}


13bbf606b7d341e395a634863a37c18a.png


java默认使用UTF-8 来进行编码, 我们可以通过查看字符编码网站 来检验 :

网址链接378ddd4cf5e742ec9b088308255f3a3b.png


换个内容试试 :

89f7bc4e6d2d48c88e4305f7f4bf23fa.png

输出 :


21d3445c664244b2b7eeeeffa62f26a6.png

对应的检验一下 :


7db3299a3c004e578c13df2c7db3093a.png

为啥结果不同呢?

因为一个汉字是由三个字符组成的, 而之前是打印每个字符的10进制, 我们可以换成 16 进制打印每个字符 :


public class Test {
    public static void main(String[] args) throws IOException {
        try(InputStream inputStream = new FileInputStream("d:/test.txt")) {
            while(true) {
                int a = inputStream.read();
                if(a == -1) {
                    break;
                }
                System.out.printf("%x\n", a);  //以 16 进制打印每个字符
            }
        }
    }
}

c3e8dba70bd147fd930fc0f24fc77a08.png


这样就对应上了.


相关文章
|
1天前
|
存储 编译器 C语言
C语言进阶⑱(文件上篇)(动态通讯录写入文件)(文件指针+IO流+八个输入输出函数)fopen+fclose(下)
C语言进阶⑱(文件上篇)(动态通讯录写入文件)(文件指针+IO流+八个输入输出函数)fopen+fclose
7 0
|
1天前
|
C语言
C语言进阶⑱(文件上篇)(动态通讯录写入文件)(文件指针+IO流+八个输入输出函数)fopen+fclose(中)
C语言进阶⑱(文件上篇)(动态通讯录写入文件)(文件指针+IO流+八个输入输出函数)fopen+fclose
8 0
|
1天前
|
存储 数据库 C语言
C语言进阶⑱(文件上篇)(动态通讯录写入文件)(文件指针+IO流+八个输入输出函数)fopen+fclose(上)
C语言进阶⑱(文件上篇)(动态通讯录写入文件)(文件指针+IO流+八个输入输出函数)fopen+fclose
8 0
|
6天前
|
存储 JSON 安全
Python中的文件操作与文件IO操作
【5月更文挑战第14天】在Python中,文件操作是常见任务,包括读取、写入和处理文件内容。`open()`函数是核心,接受文件路径和模式(如'r'、'w'、'a'、'b'和'+')参数。本文详细讨论了文件操作基础,如读写模式,以及文件IO操作,如读取、写入和移动指针。异常处理是关键,使用`try-except`捕获`FileNotFoundError`和`PermissionError`等异常。进阶技巧涉及`with`语句、`readline()`、`os`和`shutil`模块。数据序列化与反序列化方面,介绍了
18 0
|
6天前
|
Java 开发者
Java一分钟之-Java IO流:文件读写基础
【5月更文挑战第10天】本文介绍了Java IO流在文件读写中的应用,包括`FileInputStream`和`FileOutputStream`用于字节流操作,`BufferedReader`和`PrintWriter`用于字符流。通过代码示例展示了如何读取和写入文件,强调了常见问题如未关闭流、文件路径、编码、权限和异常处理,并提供了追加写入与读取的示例。理解这些基础知识和注意事项能帮助开发者编写更可靠的程序。
21 0
|
6天前
|
存储 Java
Java的`java.io`包包含多种输入输出类
【5月更文挑战第2天】Java的`java.io`包包含多种输入输出类。此示例展示如何使用`FileInputStream`从`input.txt`读取数据。首先创建`FileInputStream`对象,接着分配一个`byte`数组存储流中的数据。通过`read()`方法读取数据,然后将字节数组转换为字符串打印。最后关闭输入流释放资源。`InputStream`是抽象类,此处使用其子类`FileInputStream`。其他子类如`ByteArrayInputStream`、`ObjectInputStream`和`BufferedInputStream`各有特定用途。
51 1
|
6天前
|
C++ 数据格式
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
|
6天前
|
存储 缓存 安全
Java 中 IO 流、File文件
Java 中 IO 流、File文件
|
6天前
|
Java Unix Windows
|
6天前
|
监控 Java
Java一分钟之-NIO:非阻塞IO操作
【5月更文挑战第14天】Java的NIO(New IO)解决了传统BIO在高并发下的低效问题,通过非阻塞方式提高性能。NIO涉及复杂的选择器和缓冲区管理,易出现线程、内存和中断处理的误区。要避免这些问题,可以使用如Netty的NIO库,谨慎设计并发策略,并建立标准异常处理。示例展示了简单NIO服务器,接收连接并发送欢迎消息。理解NIO工作原理和最佳实践,有助于构建高效网络应用。
9 2

热门文章

最新文章