发布于2026-07-12 阅读(0)
扫一扫,手机访问
狭义的文件:保存在硬盘上的文件。
广义的文件:操作系统进行管理的一种机制,很多软件/硬件资源被抽象成“文件”来统一表示。
注:当前这篇文章主要讨论狭义文件。
下面这张图展示的,在计算机专业术语里叫“目录”:

一台计算机里能存很多文件,那怎么区分和识别它们呢?靠路径。
路径: 定位文件的过程。计算机的目录一层套一层,形成树形结构。从树根出发,到目标文件,中间经过的所有目录记录下来,就构成了路径。
斜杠 /:主流操作系统都用 / 分割。Windows 是个例外,它既支持 / 也支持 \(反斜杠),默认习惯用 \。
从根节点开始,逐级把路径写完整。
示例:找 E 盘 LX2 下的 test.txt 文件

绝对路径就是:E:\前端开发\实验二\LX2\test.txt
需要先确定一个基准路径,然后基于这个基准去找文件。
示例:还是找上面那个 test.txt,这次用相对路径

如果想以 E:\前端开发\实验二\LX2 为基准,那相对路径就是 ./test.txt(. 表示当前目录)。
如果以 E:\前端开发\实验二 为基准,那就是 ./LX2/test.txt。
如果以 E:\前端开发\实验二\LX2\photo 为基准,那就得用 ../test.txt(.. 表示上一级目录)。
在代码里写相对路径,基准又是什么呢?这没定数:在 IDEA 里直接运行,基准就是项目目录;如果打成 jar 包单独跑,那基准就是执行 ja va -jar 命令时所在的目录。
从开发角度,文件可以分成两大类:
怎么快速判断?最简单的办法:用记事本打开,如果能看到能懂的文字,就是文本文件;如果全是乱码,那就是二进制文件。
例子: 图片、音频、视频、可执行程序、Word 文档(.docx)都是典型的二进制文件。
例子: .txt 纯文本、.ja va、.c 都是标准的文本文件。
Ja va 通过 ja va.io.File 这个类来对文件(包括目录)进行抽象描述。注意:有 File 对象并不代表磁盘上真的存在那个文件。
File 是 Ja va 标准库(ja va.io 包)里的一个类,用来表示文件或目录的路径,并提供操作这些路径的方法。
| 修饰符及类型 | 属性 | 说明 |
|---|---|---|
static String | pathSeparator | 依赖于系统的路径分隔符,String 类型的表示 |
static char | pathSeparator | 依赖于系统的路径分隔符,char 类型的表示 |
参数 String 文件的路径,绝对路径和相对路径都行。
| 签名 | 说明 |
|---|---|
File(File parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 |
File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径 |
File(String parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示 |
| 修饰符及返回值类型 | 方法签名 | 说明 |
|---|---|---|
String | getParent() | 返回 File 对象的父目录文件路径 |
String | getName() | 返回 File 对象的纯文件名称 |
String | getPath() | 返回 File 对象的文件路径 |
String | getAbsolutePath() | 返回 File 对象的绝对路径 |
String | getCanonicalPath() | 返回 File 对象的修饰过的绝对路径 |
boolean | exists() | 判断 File 对象描述的文件是否真实存在 |
boolean | isDirectory() | 判断 File 对象代表的文件是否是一个目录 |
boolean | isFile() | 判断 File 对象代表的文件是否是一个普通文件 |
boolean | createNewFile() | 根据 File 对象,自动创建一个空文件。成功创建后返回 true |
boolean | delete() | 根据 File 对象,删除该文件。成功删除后返回 true |
void | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到 JVM 运行结束时才会进行 |
String[] | list() | 返回 File 对象代表的目录下的所有文件名 |
File[] | listFiles() | 返回 File 对象代表的目录下的所有文件,以 File 对象表示 |
boolean | mkdir() | 创建 File 对象代表的目录 |
boolean | mkdirs() | 创建 File 对象代表的目录,如果必要,会创建中间目录 |
boolean | renameTo(File dest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操作 |
boolean | canRead() | 判断用户是否对文件有可读权限 |
boolean | canWrite() | 判断用户是否对文件有可写权限 |
package demo1;
import ja va.io.File;
import ja va.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
// 此处传入的是绝对路径,getPath得到的就是绝对路径
File file = new File("E:/前端开发/实验二/LX2/test.txt");
System.out.println("父目录文件路径: "+file.getParent());
System.out.println("文件名称: "+file.getName());
System.out.println("文件路径"+file.getPath());
System.out.println("文件的绝对路径"+file.getAbsolutePath());
// 简化了绝对路径中的 . 和 ..
System.out.println("简化过后的绝对路径"+file.getCanonicalFile());
}
}
打印结果:

import ja va.io.File;
import ja va.util.Arrays;
public class Test {
public static void main(String[] args) {
File file = new File("E:/");
//list 只是列出当前目录的子元素,无法列出子目录中的具体内容
String[] list = file.list();
System.out.println(Arrays.toString(list));
System.out.println("================");
// File 对象代表的目录下的所有文件,以 File 对象表示
File[] list2 = file.listFiles();
System.out.println(Arrays.toString(list2));
}
}
打印结果:

当前文件夹下为空,我们可以通过 mkdir() 创建目录:

public class Test {
public static void main(String[] args) {
File file = new File("E:/新建文件夹/text");
System.out.println(file.mkdir());
}
}
打印结果:

看,文件夹下多了一个叫 text 的目录:

1. 文件是存储在硬盘上的。
2. 目录也是文件,操作系统通过树形结构组织目录和文件。
3. 通过路径定位到具体的文件。
4. 文件分为:文本文件和二进制文件。
Ja va 中操作文件内容,核心是靠一组“流”来实现的。
计算机里的“流”和水流很像:我们把数据想象成连续不断的字节序列,就像水管里流动的水。水有什么特点?你可以一桶接满(一次取 100 升),也可以用两个 50 升的桶分两次接,或者用 10 个 10 升的桶……只要总量是 100 升,取水方式随便拆。
文件流也一样:计算机把文件内容看作一段连续的字节流(byte stream)。读取时,你可以一次 read(100) 全部读完,也可以循环 10 次每次 read(10),甚至一次读 1 字节读 100 次。只要每次读的字节数加起来正好是 100,并且按顺序读,都能拿到完整内容。
因此,计算机里读写文件,用的就是“流”(Stream)这个概念。
流的种类有好几十,但可以分两大类:
InputStream输入:从文件读数据OutputStream输出:往文件写数据
Reader输入Writer输出
那“输入”和“输出”怎么理解?很简单,看数据流向:从硬盘到 CPU 是输入,从 CPU 到硬盘是输出。
| 修饰符及返回值类型 | 方法签名 | 说明 |
|---|---|---|
| int | read() | 读取一个字节的数据,返回 -1 代表已经完全读完了 |
| int | read(byte[] b) | 最多读取 b.length 字节的数据到 b 中,返回实际读到的数据;-1 代表已经读完了 |
| int | read(byte[] b, int off, int len) | 最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数据;-1 代表已经读完了 |
| void | close() | 关闭字节流 |

三步走:
1. 打开文件
2. 读
3. 关闭
先创建一个名为 text.txt 的文件,内容写为 hello:

import ja va.io.FileInputStream;
import ja va.io.IOException;
import ja va.io.InputStream;
public class Test {
public static void main(String[] args) throws IOException {
// InputStream是抽象类,不能直接new
// 创建对象成功就相当于去打开文件
// try with resources 只要出现try代码块就会自动调用close
try(InputStream inputStream = new FileInputStream("./text.txt")){
while (true){
int i = inputStream.read();
if(i ==-1){
break;
}
System.out.println(i);
}
}
}
}
打印结果:hello 这几个字母对应的 ASCII 码值:

把 text.txt 里的内容改成“你好”:

如果文件里包含非 ASCII 字符(比如中文“你”“好”),在 UTF-8 编码下,这些字符通常占多个字节。
一次读一个字节:
import ja va.io.FileInputStream;
import ja va.io.IOException;
import ja va.io.InputStream;
public class Test {
public static void main(String[] args) throws IOException {
// InputStream是抽象类,不能直接new
// 创建对象成功就相当于去打开文件
// try with resources 只要出现try代码块就会自动调用close
try(InputStream inputStream = new FileInputStream("./text.txt")){
while (true){
// 一次读一个字节
int i = inputStream.read();
if(i ==-1){
break;
}
// 这里打印十六进制 一个十六进制数字是4个比特位,两个十六进制数字就是1一个字节,所以选择用十六进制来进行打印核对
System.out.printf("%x\n",i);
}
}
}
}
打印结果:

和上面“你好”的 UTF-8 码表完全对应上了。
一次读多个字节:
public class Test {
public static void main(String[] args) throws IOException {
try(InputStream inputStream = new FileInputStream("./text.txt")) {
//一次读多个字节 数组的长度自行定义
byte[] data = new byte[3];
// 此处的读操作尽可能让数组填满,
// 填不满的话,能填几个是几个
while (true){
// 此处的n是实际读到的字节数
int n = inputStream.read(data);
if(n == -1){
// 读完了
break;
}
for(int i = 0; i
打印结果(一次读三个字节):

5.3 OutputStream 概述
1. 方法
修饰符及返回值类型 方法签名 说明 void write(int b) 写入一个字节的数据 void write(byte[] b) 将 b 这个字节数组中的数据全部写入输出流中 void write(byte[] b, int off, int len) 将 b 这个字节数组中从 off 开始的数据写入输出流中,一共写 len 个 void close() 关闭字节流 void flush() 重要:我们知道 I/O 的速度是很慢的,所以,很多 OutputStream 为了减少设备操作的次数,在写数据的时候会先将数据暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中。这个区域一般称为缓冲区。但这会造成一个结果:我们写的数据很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置调用 flush()(刷新)操作,将数据刷到设备中。

这里的参数是 int,主要是因为希望参数的取值范围为 0~255——Ja va 里没有 unsigned 类型。
2. 使用
示例:在 output.txt 文件中写入 abc
当前目录下没有 output.txt,可以看看代码运行后会不会自动创建并写入:

import ja va.io.*;
public class Test {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("output.txt")){
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果: 果然,新创建了一个 output.txt 并写入了 abc:

对于 OutputStream 来说,如果文件不存在,它会尝试创建文件再写入。
注意: OutputStream 打开文件的那一刻,会把文件原来的内容清空。换句话说,是覆盖写入。
示例:把刚写的 abc 改为大写的 ABC
import ja va.io.*;
public class Test {
public static void main(String[] args) {
try(OutputStream outputStream = new FileOutputStream("output.txt")){
byte[] bytes = {65,66,67};
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果:

5.4 Reader 的使用

示例:把 text.txt 文件中的 abc 读出来
import ja va.io.FileReader;
import ja va.io.IOException;
import ja va.io.Reader;
public class Test {
public static void main(String[] args) {
try(Reader reader = new FileReader("text.txt")){
while (true){
int n = reader.read();
if(n == -1){
break;
}
System.out.println((char ) n);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
打印结果:

5.5 Writer 的使用
将 writer.txt 中写入 hello world
import ja va.io.FileWriter;
import ja va.io.IOException;
import ja va.io.Writer;
public class Test {
public static void main(String[] args) {
try(Writer writer = new FileWriter("./writer.txt")){
writer.write("hello world");
} catch (IOException e) {
e.printStackTrace();
}
}
}
打印结果:

在原来的 hello world 基础上追加写 hello world
public static void main(String[] args) {
//追加再写一次hello world
try(Writer writer = new FileWriter("./writer.txt",true)){
writer.write("hello world ");
} catch (IOException e) {
e.printStackTrace();
}
}
}
打印结果:

以上就是 Ja va 文件操作与 IO 流(File 类 + 字节流 + 字符流)的核心内容。从文件的概念、路径到实际读写的各个 API,相信动手敲一遍就会印象深刻。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8