文件
文件:在硬盘上存储数据的方式
操作系统帮我们把硬盘的细节封装了
我们只需要了解文件相关的接口即可
文件系统:
不同的文件系统 管理的方式都是类似的
通过目录-文件 构成了N叉树 的树型结构(directory)
路径
我们可以通过D盘->tmp->cat.jpg通过这个路径就能找到电脑上的唯一一个文件这个东西就叫路径
**绝对路径:**以盘为开头的路径 例如d:/tmp/cat.jpg
**相对路径:**以 . 或者 … 开头的路径叫做"相对路径" 相对路径需要有一个基准目录,工作目录表示从这个基准目录出发 怎么走才能找到这个目录
例如以D:为基准 ./tmp/cat.jpg
如果以D:/tmp为基准./cat.jpg
如果以D:/tmp/111为基准…/cat.jpg(…表示上一层目录)
如果以D:/tmp/111/aaa为基准
…/…/cat.jpg
文件系统上存储的文件 具体来说分为两个大类
- 文本文件
存储字符(utf8表上数据的组合) - 二进制文件
二进制的数据
使用记事本打开文件如果打开后是能看懂的就是文本
打开后看不懂的就是二进制
记事本打开文件就是尝试把当前数据在码表中进行查询
Java中的文件系统操作
java.io.File类
IO input和output (输入输出)
硬盘输入到内存为input
内存输入到硬盘位output
(数据靠近cpu输入 数据原理cpu输出)
通过File对象描述一个具体的文件
构造方法
| 签名 | 说明 |
|---|---|
| File(File parent, String child) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例 |
| File(String pathname) | 根据文件路径创建一个新的 File 实例,路径可以是绝对路径或者相对路径 |
| File(String parent, Stringchild) | 根据父目录 + 孩子文件路径,创建一个新的 File 实例,父目录用路径表示 |
注意: windows上的目录之间的分隔符 可以使用/也可以使用\
方法
| 修饰符及返回值类型 | 方法签名 | 说明 |
|---|---|---|
| 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() | 判断用户是否对文件有可写权限方法 |
例如:
public class Demo1 {
public static void main(String[] args) throws IOException {
File file = new File("./test.txt");
System.out.println(file.getParent());
System.out.println(file.getName());
System.out.println(file.getPath());
System.out.println(file.getAbsoluteFile());//把工作目录拼接上当前目录
System.out.println(file.getCanonicalFile());//整理过后的绝对目录
}
}

示例2:
public class Demo2 {
public static void main(String[] args) {
File file = new File("./test.txt");
System.out.println(file.exists());
System.out.println(file.isFile());
System.out.println(file.isDirectory());
}
}

例3:
public class Demo2 {
public static void main(String[] args) throws IOException {
File file = new File("./test.txt");
file.createNewFile();//创建文件
System.out.println(file.exists());
System.out.println(file.isFile());
System.out.println(file.isDirectory());
}
}

file.createNewFile();
这个操作可能会抛出异常
比如写入到文件时非法路径
比如创建的文件对于所在目录没有权限操作
删除文件
public class Demo3 {
public static void main(String[] args) {
File file = new File("./test.txt");
file.delete();
}
}
public class Demo3 {
public static void main(String[] args) throws InterruptedException {
File file = new File("./test.txt");
//file.delete();
file.deleteOnExit();//等到程序退出再删除
Thread.sleep(2000);
}
}
临时文件会用到这样的功能 等到程序结束临时文件自动删除
示例3
创建目录
public class Demo4 {
public static void main(String[] args) {
File file = new File("./testDir");
//mk = make dir = directory
file.mkdir();//只能创建一层目录
//file.mkdirs();//可以创建多层目录
}
}
public class Demo4 {
public static void main(String[] args) {
File file = new File("./testDir/111/222/333");
//mk = make dir = directory
//file.mkdir();//只能创建一层目录
file.mkdirs();//可以创建多层目录
}
}

示例4
重命名文件
public class Demo5 {
public static void main(String[] args) {
File file = new File("./test.txt");
File file1 = new File("./src/test.txt");
file.renameTo(file1);
}
}
以上文件系统的操作 都是基于File类来完成的另外还需要文件内容的操作
文件流 stream
文件这里的内容本质时来自于硬盘 硬盘又是操作系统管理的
使用某个编程语言操作文件 本质上都是需要调用系统的api
其核心步骤有四个
- 打开文件 fopen
- 关闭文件 fclose
- 读文件 fread
- 写文件 fwrite
一系列类
有两大类
字节流
InputStream
OutputStream
后续的一些操作字节的类衍生自这两个类 是以字节位单位操作(二进制文件)
字符流
Reader
Writer
后续操作字符的类 衍生自这两个类 操作单位是字符为单位(文本文件)
Java IO流是一个庞大的体系 涉及到非常多的类这些不同类 都有各自不同的特性 但总的来说 使用方法都是类似的
- 构造方法 打开文件
- close方法 关闭文件
- 如果衍生自InputSstream 或者 Read 旧可以使用read方法来读去数据
- 如果衍生自OutputStream 或者 Writer 就可以使用write 方法来写数据源了
示例:
我们创建一个文档

public class Demo6 {
public static void main(String[] args) throws IOException {
Reader reader = new FileReader("C:\\Users\\86188\\Desktop\\test.txt");//Reader是抽象类需要一个FileReader继承
reader.close();
}
}
打开文件 fopen和关闭文件 fclose
使用Reader类读取
Reader reader = new FileReader()
Reader是抽象类需要一个FileReader继承,写文件路径 相对路径和绝对路径都行
reader.close();
文件泄露问题
这个操作非常重要 释放必要资源 让一个进程打开一个文件 是要从系统这里申请一定的资源
(占用进程的pcb里的文件描述符表中的一个表项) 是一个顺序表长度有限不会自动扩容
如果不释放就会出现 文件资源泄露 而且一旦一直打开文件而不去关闭文件 文件描述符表就会被占满 后续就无法继续打开新的文件了
如果上述代码中间抛出异常或者 return close旧都执行不到了 可能会发生文件资源泄露
所以我们需要用finally执行close()
public class Demo6 {
public static void main(String[] args) throws IOException {
Reader reader = new FileReader("C:\\Users\\86188\\Desktop\\test.txt");//Reader是抽象类需要一个FileReader继承
try{
}finally {
reader.close();
}
}
}
或者使用
public class Demo6 {
public static void main(String[] args) throws IOException {
try(Reader reader = new FileReader("C:\\Users\\86188\\Desktop\\test.txt")){
}
}
}
只要try代码块使用完毕了 就会自动调用close方法
读文件read
| 修饰符及返回值类型 | 方法签名 | 说明 |
|---|---|---|
| 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() | 关闭字节流 |
我们在编译器可以看到

read()一次是读一个字节 那为什么返回值是int呢?
这是因为
我们可以查看源码


返回:字符读取,作为0到65535(0x00-0xffff)范围内的整数,或者-1(如果结束)。
读取的字符是按照一个整型去表示的 而整数的范围是0到65535(正是两个字节的范围) -1(eof)则是表示到达文件末尾读取完毕(windows 上可以通过ctrl+z输入eof linux可以输入ctrl+d输入eof)
我们的文件是utf8格式 一个字符应该是3个字节 为什么这里是两个字节呢?
java的char类型是使用unicode编码的(一个字符两个字节)时用这个方法读取读取一个字符 java标准库会帮助我们自动转换

一次读多个字符 会把读到的内容填充到参数这个cbuf数组中 此处的参数 相当于是一个"输出型参数" 通过read 会把一个空的数组填充上内容
例如:


n表示实际读取的字符个数 如果文件>1024就会把数组填满 如果文件<1024就会返回实际读到的字符个数

有的时候 可能会涉及到有许多个小文件都需要读取并且拼接到一起
就可以用到这个方法
例如:
3个文件每个文件大小时100字节
read(cbuf,100,200);
就会把文件读取到这个位置

往往读一个比较大的文件 需要循环读取
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class Demo6 {
public static void main(String[] args) throws IOException {
try(Reader reader = new FileReader("C:\\Users\\86188\\Desktop\\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.print(buf[i]+" ");;
}
}
}
}
}

InputStream
InputStream就是字节流 用法和Reader非常相似
文本文件,也可以已使用字节流打开 只不过此时读到的每个字节 就不是完整的字符

字节流的方法和字符流的相似
只不过返回的整数是一个0~225的整数

同样是返回-1结束
字节流以十六进制的方式打印文件
public class Demo7 {
public static void main(String[] args) throws IOException {
try (InputStream inputStream = new FileInputStream("C:\\Users\\86188\\Desktop\\test.txt")) {
while (true){
byte[] buf = new byte[1024];
int n = inputStream.read(buf);
if (n == -1) {
break;
}
for (int i = 0; i < n; i++) {
System.out.printf("%x ",buf[i]);
}
}
}
}
}

每个字节按照十六进制打印
正好是"你好世界"的编码对应的十六进制
可以使用一些工具类 完成字节/字符 =>字符串的转换
我们可以使用
Scanner scanner = new Scanner(System.in);
打开.in的源码可以看到

也是一个InputStream类的对象
在操作系统中"文件"是一个广义的概念Sysyem.in是一个特殊的文件对应到"标准输入"普通硬盘上的文件也是文件 后面的网络编程 网卡(socket)也是文件
Scanner都是一视同仁只是把当前读到的字节数据进行转换 不关心这个数据究竟是来自于标准输入 还是文件 还是网卡
public class Demo8 {
public static void main(String[] args) throws IOException {
try(InputStream inputStream = new FileInputStream("C:\\Users\\86188\\Desktop\\test.txt")){
Scanner scanner = new Scanner(inputStream);
String s = scanner.next();
System.out.println(s);
}
}
}

Scanner的操作在这都能使用
但是要注意 Scanner只能用来读文本文件 不适合读取二进制文件
输出write
输出使用方法和输入相似
public class Demo9 {
public static void main(String[] args) throws IOException {
try(Writer writer = new FileWriter("C:\\Users\\86188\\Desktop\\test.txt")){
writer.write("hello java");
}
}
}

输出流对象(无论是字节流还是字符流打开文件后会清空文件内容)
还可以按照追加写方式打开


OutputStream使用方式完全一样
只不过不能支持字符串参数 只能按照字节 或者字节数组来写入
本文详细介绍了Java中的文件系统操作,包括File类的使用、文件路径管理、文件类型(文本和二进制)、文件流(InputStream和OutputStream)的打开、关闭、读写,以及文件泄露问题的处理。
853

被折叠的 条评论
为什么被折叠?



