在这里插入图片描述

跟 Java 聊聊 “文件那点事儿”:从不会 IO 到敢操作文件的小笔记

你肯定有过这样的经历吧,手机里存了一堆照片,想导到电脑里;写了一半的日记,关掉记事本再打开还能接着写。这些日常操作,本质上都是 “数据在存储设备和程序之间搬家”。而在 Java 世界里,干这活儿的技术就叫 “文件 IO”。至于Java 是怎么和文件 “打交道” 的,听我娓娓道来。

首先搞懂:IO 到底是个啥?

IO,全称是 Input/Output,翻译过来就是 “输入 / 输出”。说白了,就是程序和 “外部存储”(比如硬盘、U 盘)之间的 “沟通桥梁”。
你其实也可以这么理解:

  • 当程序从文件里 “拿东西”(比如读一篇文章),这叫Input(输入);
  • 当程序往文件里 “塞东西”(比如保存一段文字),这叫Output(输出)。

就像你和朋友写信:你写好信寄出去(Output),朋友收到信读内容(Input)—— 文件就是你们之间的 “信封”,而 Java 的 IO 工具,就是那个 “邮递员”。

或许还可以再生动一点,假设你的屁股上坐在硬盘上,此刻有一阵风袭来,迎面而来是输入,离你而去就是输出。

第一步:认识文件的 “身份证”——File 类

搞懂IO是个啥了,是不是就可以开始操作文件了,当然不行了,如果你要操作文件是不是事先知道文件在哪个位置,其中Java中就提供了个叫File的类,它就像文件的 “身份证”,通过“身份证”内的信息(方法),能告诉你文件的名字、位置、大小,甚至能判断这是个文件还是文件夹。总而言之File是用来操作文件系统

1.1File 概述

File类中的多个属性,构造方法和方法,我会着重讲解几个常见的,也是学文件操作比较重要的。
构造方法

签名 说明
File(File parent, String child) 根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实例
File(String pathname) 根据⽂件路径创建⼀个新的 File 实例,路径可以是绝对路径或者相对路径
File(String parent, String child) 根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实例,⽗⽬录⽤路径表⽰

在这里插入图片描述

属性

修饰符及类型 属性 说明
static String pathSeparator 依赖于系统的路径分隔符,String类型的表⽰
static char pathSeparator 依赖于系统的路径分隔符,char 类型的表示

在这里插入图片描述

疑问,为什么在Windonws上分隔符是\而其他系统上不是呢?
Windows 的前身叫做 DOS 系统,命令行的系统微软最开始做的产品,就是 DOS真正开始搞 windows 的时候,DOS 就是通过\来进行分割.所以就一直继承了下来,当然Windowns本身是可以使用/的,但是在编程中/会被当成转义符,所以如果在idea中如果要使用 / 来当分隔符,得再在 / 上加个 / ,就可以了,所以还是建议直接使用 \ 更好些。

在这里插入图片描述
在这里插入图片描述

方法
在这里插入图片描述

是不是有点太多了,不用怕,不用死记硬背,现在先留个印象,到后续真实开发,用到的时候再去查,用多了就自然而然得熟练了。

1.2 代码演练

1.2.1 构造File实列化对象

File file1=new File("H:/javaFileTest/FileTestDemo/text.txt");//绝对路径
File file2=new File("./text.txt");//相对路径

在这里插入图片描述
1.2.2 File常用的方法演示

1. getParent()
返回 File 对象的⽗⽬录⽂件路径

File file=new File("H:/javaFileTest/FileTestDemo/text.txt");
System.out.println(file.getParent());

在这里插入图片描述
执行后打印结果:
在这里插入图片描述
2.getName()
返回 FIle 对象的纯⽂件名称

File file=new File("H:/javaFileTest/FileTestDemo/text.txt");
System.out.println(file.getName());

执行后打印结果:
在这里插入图片描述
3.getPath()

返回 File 对象的⽂件路径

File file=new File("H:/javaFileTest/FileTestDemo/text.txt");
System.out.println(file.getPath());

在这里插入图片描述

执行后打印结果:
在这里插入图片描述
4.getAbsolutePath()
返回 File 对象的绝对路径

File file2=new File("./text.txt");
System.out.println(file2.getAbsolutePath());

在这里插入图片描述

在这里插入图片描述
执行后打印结果:
在这里插入图片描述
5.getCanonicalPath()
返回 File 对象的修饰过的绝对路径

File file2=new File("./text.txt");
System.out.println(file2.getCanonicalPath());

在这里插入图片描述
执行后打印结果:
在这里插入图片描述
6.exists()
判断 File 对象描述的⽂件是否真实存在

File file =new File("H:/javaFileTest/FileTestDemo/text.txt");
System.out.println(file.exists());

在这里插入图片描述
执行后打印结果:

在这里插入图片描述

7.isFile() / isDirectory()
判断 File 对象代表的⽂件是否是⼀个普通⽂件/判断 File 对象代表的⽂件是否是⼀个⽬录

File file =new File("H:/javaFileTest/FileTestDemo/text.txt");
System.out.println(file.isFile());
File file2 =new File("H:/javaFileTest/FileTestDemo");
System.out.println(file2.isDirectory());

在这里插入图片描述

在这里插入图片描述
8. createNewFile() / delete()
创建文件和删除文件

File file =new File("./text.txt");
file.createNewFile();
file.delete()

在这里插入图片描述
9.deleteOnExit();
根据 File 对象,标注⽂件将被删除,删除动作会到 JVM 运⾏结束时才会进行

 File file=new File("./test.txt");
        //根据 File 对象,删除该⽂件。成功
        //删除后返回 true
        boolean result=file.delete();
        //进程在退出时删除文件
        file.deleteOnExit();
        Thread.sleep(10000);

在这里插入图片描述
10.list() / listFiles()
返回File对象代表的目下的所有文件名 / 返回 File 对象代表的⽬录下的所有⽂件,以 File 对象表⽰

				//针对文件是无法进行list的
        File file1=new File("./");
        String[] list=file1.list();
        System.out.println(Arrays.toString(list));
        File[] files=file1.listFiles();
        System.out.println(Arrays.toString(files));

在这里插入图片描述

list 只是列出当前目录里面的子元素无法列出子目录中的内容(孙子元素)

11.mkdirs();
创建 File 对象代表的⽬录,如果必要,会创建中间⽬录

		File file=new File("./test/111/222");        
        //mkdir 无法创建多级目录,只能创建一级
		file.mkdir();
		file.mkdirs();

在这里插入图片描述
12.renameTo()
进⾏⽂件改名,也可以视为我们平时的剪切、粘贴操作

 File file = new File("./test2");
        File newFile = new File("./src/test2");
        boolean result = file.renameTo(newFile);
        System.out.println(result);

在这里插入图片描述

第二步:开始 “干活”—— 读写文件的两种 “快递员”

知道文件在哪儿之后,就得让 “邮递员” 上场了。Java 中针对文件内容的操作主要是通过 一组"流对象"来实现的,Java 里有两种主流 “邮递员”:字节流字符流

流~~
形象的比喻~~
水流~~
要接 100 ml 水~
1次把 100ml 都接完
分2次,-次接 50ml
分10次,-次接 10ml
分100次,一次接 1ml
无数种接水方法~~
计算机中的"流”和水流非常相似的
从文件读取 100字节 数据
1次把 100 字节都读完
分2次,一次读 50字节
分10次,一次读 10 字节
分100次,一次读1字节
无数种读数据的方法
因此, 计算机中针对读写文件,也是使用 流(Stream) 词
流是操作系统层面的术语,和语言无关各种编程语言操作文件,都叫流~~
Java中表示流的类非常多,此处就搞懂常见的8个就够了

1. 字节流:

读写文件,以字节为单位,是针对二进制文件使用的,像是啥都能搬的 “万能快递员”,因为所有文件本质上都是由 “字节”(0 和 1 组成的最小单位)构成的,所以不管什么文件(文本、图片、视频、音频),它都能“搬”。

1.1 InputStream

字节输入流,简单的讲就是从文件中读数据,但是InputStream本身是个抽象类,不能实例化,所以我们只能调用它的子类们,因为只关⼼从⽂件中读取,所以使
FileInputStream
在这里插入图片描述
FileInputStream 概述
构造方法:

签名 说明
FileInputStream(File file) 利⽤ File 构造⽂件输⼊流
FileInputStream(String name) 利⽤⽂件路径构造⽂件输⼊流

实例化FileInputStream对象:
打开文件:
在这里插入图片描述

注意:文件必须存在,否则报错,只要文件存在才能读取内容。

在这里插入图片描述
关闭文件:
在这里插入图片描述

接下来我们写一个完整过程:
在这里插入图片描述
但是有标红,我们来分析:
在这里插入图片描述

在这里插入图片描述
把异常抛出后,我们也没有发现代码好像有点不好看,现在可是看脸的社会,根本仍不了,所以在Java1.5后引入了try-with-resources

在这里插入图片描述
read()方法:
在 Java 的InputStream体系中,read()方法是 “字节读取” 的核心 —— 它就像连接程序与数据源的 “吸管”,负责把字节从数据源(文件、网络等)一点点 “吸” 到程序里。但这个方法的细节远比 “读字节” 三个字复杂,尤其是返回值设计和不同重载版本的区别,新手很容易踩坑。

在这里插入图片描述
读文件操作代码演示:

 try (InputStream inputStream=new FileInputStream("./test.txt")){
            //读文件操作
            while(true){
                //一次读一个字节
//                int data=inputStream.read();
//                    if (data==-1){
//                        //文件读完
//                        break;
//                    }
//                System.out.println(data);
                //一次读多个字节,数组的长度,自行定义
                byte[] data=new byte[4];
                //读操作,就会尽肯把字节数组给填满
                //填不满的话,能填几个就是几个
                //此处的 n 就表示实际读了几个字节
                int n=inputStream.read(data);
                if (n==-1){
                    //文件读完
                    break;
                }
                for (int i = 0; i <n ; i++) {
                    System.out.printf("0x%x\n",data[i]);

                }
                System.out.println("================");

            }
        }

在这里插入图片描述

test.txt内容
在这里插入图片描述

运行结果
在这里插入图片描述

1.2 OutputStream

OutputStream 同样只是⼀个抽象类,要使⽤还需要具体的实现类。我们现在还是只关⼼写⼊⽂件中,所以使⽤ FileOutputStream

FileOutputStream概述:

实例化FileOutputStream对象

对于OutputStream来说,如果有这个文件会打开,没有这个文件会尝试创建不存在的文件
在这里插入图片描述

write()方法
write()是OutputStream类的核心方法(OutputStream是所有字节输出流的抽象基类),作用是将字节数据写入输出流关联的目标(比如文件、网络套接字、内存缓冲区等)。
和InputStream的read()类似,write()也有三个重载方法,分别对应 “单个字节”“字节数组”“部分字节数组” 的写入场景,覆盖了不同的输出需求。
在这里插入图片描述

为什么用int?
参数的取值范围,0-255
如果用 byte 表示,-128->+127
Java 没有 unsigned 类型!!
为啥不用 short??(short 类型可以忘记了)
-32768 =>32767
内存空间在 2024 年,不是主要矛盾了~~

写文件操作代码演示:

try(OutputStream outputStream=new FileOutputStream("./output.txt")){
            //97在ascii中就是‘a’
            outputStream.write(97);
            outputStream.write(98);
            outputStream.write(99);
            byte[] bytes={99};
            outputStream.write(bytes);
          
        }  catch (IOException e) {
            //此处是需要处理两个异常,由于此处并没有针对这两个异常提供不同处理,就直接合并了。
            e.printStackTrace();
        }

在这里插入图片描述

代码结果在这里插入图片描述

2. 字符流

字节流虽然万能,但处理文本时有点麻烦 —— 每次都要转字节。这时候就该 “字符流”(Reader/Writer)出场了,它专门处理文本文件(.txt、.java 等),直接认 “字符”(比如汉字、字母),不用来回转换。
就像专门送信件的快递员,知道信件里是文字,不用拆箱就能处理。

2.1 reader

write()是OutputStream类的核心方法(OutputStream是所有字节输出流的抽象基类),作用是将字节数据写入输出流关联的目标(比如文件、网络套接字、内存缓冲区等)。
InputStreamread() 类似,read() 也有三个重载方法,分别对应 “单个字节”“字节数组”“部分字节数组” 的写入场景,覆盖了不同的输出需求。
在这里插入图片描述
读文件操作代码演示:

try(Reader reader=new FileReader("./test.txt")){
            while (true){
                char[] buf=new char[1024];
                int n=reader.read(buf);
                if (n==-1){
                    break;
                }
                for (int i = 0; i <n ; i++) {
                    System.out.println(buf[i]);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

在这里插入图片描述

2.2 writer

Writer 的核心是 write() 方法,和 Readerread() 对应,但方向相反 —— 它把字符 “送出去”。相比字节流的 write(),字符流的 write() 更灵活,直接支持字符、字符数组、字符串等类型。

write() 重载方法中的参数与 read() 类似,这里就不多赘述
写文件操作代码演示:

public static void main(String[] args) {
        try(Writer writer=new FileWriter("./output.txt")){
            writer.write("Hello,world!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

第三步:总结

Java 文件 IO 核心围绕三类工具:File类负责管理文件 / 文件夹的路径、存在性等外在信息;字节流(InputStream/OutputStream) 直接操作字节,适用于所有数据(尤其是图片、视频等二进制文件),配合缓冲流可提升效率;字符流 (Reader/Writer) 处理文本,自动完成编码转换,适合.txt 等文本文件,BufferedReader/BufferedWriter的按行读写和跨平台换行很实用。关键是按场景选工具(二进制用字节流,文本用字符流),明确编码避免乱码,并用try-with-resources确保流关闭。
在这里插入图片描述

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐