一.什么是文件?
文件是一种在硬盘上存储数据的方式,操作系统帮我们把硬盘的一些细节都封装起来了,程序员只需要了解文件相关的接口即可,相当于操作文件就是间接的操作硬盘了,
硬盘用来存储数据,和内存相比硬盘的存储空间更大,访问速度更慢,成本更低,持久化存储,操作系统通过“文件系统”这样的模块来管理硬盘

别看我电脑上有c盘d盘,但是我电脑只装载着一块硬盘,操作系统可以通过文件系统把这个硬盘抽形成多个硬盘就如我的CD两盘,NTFS是windows上的文件系统,背后有一定的格式来组织硬盘的数据,EXT4是Linux上的文件系统
不同的文件系统管理文件的方式都是类似的
通过目录(directory,平常叫文件夹,专业术语叫目录)构成了N叉树的树形结构
我们在文件系统中都是通过路径来确定一个具体的文件


同样是一个cat.jpg文件,站在不同的基准目录上,查找的路径是不相同的
文件系统上存储的文件,具体来说又分成两大类
1.文本文件–存储的是字符
字符怎么定义呢?
有个表叫utf8,这个表上数据的组合就是字符
2.二进制文件–存储的是二进制数据
判断文本文件和二进制文件最简单的方式就是
直接用记事本打开,如果打开之后能看懂,就是文本,否则就是二进制像word文档,ppt,excel这些,如果托到记事本上,都是二进制文件,虽然word文档里存的东西是汉字等可以看懂的内容,但是word文档不仅仅包含我们自己输入的内容,还有行间距,文字格式等众多内容
但是如果把excel的后缀改成csv格式,就是文本文件了
utf8是文件的编码格式,此时一个汉字是三个字节的大小,在java中采用的编码格式是unicode,一个汉字是两字节的大小正好能放进char类型,那么java操作文件的时候不做处理肯定会出现问题,但是JVM已经处理好了
二.Java标准库中的操作文件类
操作文件可以理解成通过java代码把你硬盘的文件删除修改创建等,也就是通过java代码操作文件系统
Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意, File 对象可以对应到一个真实存在的文件,也可以对应到一个不存在的文件

所有外部设备(包括硬盘)向系统传输数据的过程,对CPU 而言都属于"输入操作"。

File类里面的方法
获得文件路径
import java.io.File;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
//File file = new File ("D:\\JavaEE\\java-ee-beginner\\test.txt");//绝对路径
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.getAbsolutePath());//获得绝对路径
System.out.println(file.getCanonicalPath());//获得规范路径(去除..等)
}
}

创建文件和判断文件
import java.io.File;
import java.io.IOException;
public class Demo {
public static void main(String[] args) throws IOException {
File file = new File("D:\\JavaEE\\java-ee-beginner\\test.txt");
file.createNewFile();// 创建文件
System.out.println(file.exists());// 判断文件是否存在
System.out.println(file.isFile());// 判断是否是文件
System.out.println(file.isDirectory());// 判断是否是目录
}
}

文件跟目录的区别可以认为是文件是这个路径的终点,而目录下面还有别的路径

删除文件
import java.io.File;
public class Demo {
public static void main(String[] args) {
File file=new File("./test.txt");
file.delete();
}
}
import java.io.File;
public class Demo {
public static void main(String[] args) throws InterruptedException {
File file=new File("./test.txt");
//不是立刻删除,等到程序运行结束再删除
file.deleteOnExit();
Thread.sleep(2000);
//程序运行两秒会结束,所以这个文件在两秒之后删除
}
}

创建目录
public static void main(String[] args) {
File file1 = new File("./testDir");
File file2 = new File("./testDir/111/222");
// mk => make dir => directory
// mkdir 一次只能创建一层目录. mkdirs 可以一次创建多级目录
file1.mkdir();
//file2.mkdirs();//创建多级目录
}
列出目录内容
mport java.io.File;
import java.util.Arrays;
public class Demo4 {
public static void main(String[] args) {
//File file = new File("./test.txt");
/*//文件是无法进行list(列出当前目录下的文件)
String[] list = file.list();
System.out.println(Arrays.toString(list));*/
File file = new File("D:\\JavaEE\\java-ee-beginner");
String[] list = file.list();//列出当前目录下的文件
System.out.println(Arrays.toString(list));
File[] files = file.listFiles();//列出当前目录下的文件(前缀带路径) 用File来接受
System.out.println(Arrays.toString(files));
}
}

文件重命名
import java.io.File;
public class Demo {
public static void main(String[] args) {
File file = new File("./test.txt");
File file2 = new File("./test2.txt");
boolean result = file.renameTo(file2);//把file重命名为file2
}
}
mport java.io.File;
public class Demo {
public static void main(String[] args) {
/*File file = new File("./test.txt");
File file2 = new File("./test2.txt");
boolean result = file.renameTo(file2);//把file重命名为file2*/
File file = new File("./test2.txt");
File nweFile = new File("D:\\JavaEE\\java-ee-beginner\\20250607-File\\test2.txt");
boolean result = file.renameTo(nweFile);//重命名操作还能起到移动文件的作用
/**
* 从操作系统的角度来看,重命名操做和移动操作(剪切)本质是一致的 移动操作极快,时间复杂度o1 (如果跨硬盘了就很慢了(复制+删除))
* 复制文件,时间复杂度o(n),文件/目录里所有的数据,遍历,再写入写的文件/目录
*/
System.out.println(result);
}
}
对文件内容操作



Reader类
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
// Reader 使用.
public class Demo
{
public static void main(String[] args) throws IOException
{
// FileReader 构造方法, 可以填写一个文件路径(绝对路径/相对路径都行), 也可以填写一个构造好的 File 对象
// Reader reader = new FileReader("。/test.txt");
// try {
// // 中间的代码无论出现啥情况, close 都能保证执行到.
// } finally {
// // 抛出异常, 或者 return, close 就都执行不到了~~
// reader.close();
// }
// 上述使用 finally 的方式能解决问题, 但是不优雅.
// 使用 try with resources 是更好的解决方案.
try (Reader reader = new FileReader("d:/test.txt"))
{
while (true) {//一直
/* int c = reader.read();//返回值int(最大值0xFFFF两个字节的最大值)
if (c == -1) {
break;
}
System.out.println((char) c);*/
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]);
}
}
}
}






InputStream类
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class Demo {
public static void main(String[] args) throws IOException {
try (InputStream inputStream = new FileInputStream("./test.txt")) {//出了try块,资源会自动释放,相当于自动调用inputStream.close()
//读文件操作
while (true) {
/*int date = inputStream.read();//不带参数表示读取一个字节
if (date == -1) {
//读完文件
break;
}
System.out.printf("0x%x\n", date);*/
//一次读取多个字节,数组长度进行自定义
byte[] bytes = new byte[3];
//读操作,就会尽可能把字节数组给填满
//填不满的话,能填几个就是几个
int len = inputStream.read(bytes);
System.out.println("len= " + len);
//len就是表示实际读取了几个字节
if (len == -1) {
//读完文件
break;
}
for (int i = 0; i < len; i++) {
System.out.printf("0x%x \n", bytes[i]);//打印每个字节的十六进制数
}
System.out.println("===========");
}
}
}
}
于是我们可以借助Scanner来完成上述操作
平时我们输入是
Scanner scanner=new Scanner(System.in);
那么system.in的类型也是一个InputStream

所以就有以下操作
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;
public class Demo {
public static void main(String[] args) throws IOException
{
try (InputStream inputStream = new FileInputStream("./test.txt"))
{
Scanner scanner = new Scanner(inputStream);
// 此时就是从 test.txt 这个文件中读取数据了!!
String s = scanner.next();
System.out.println(s);
}
}
}
Scanner只是用来读取文本文件,不适合读取二进制文件,标准库中需要用到一些其他类
Write类

mport java.io.*;
public class Demo {
public static void main(String[] args) {
try (Writer writer = new FileWriter("./output.txt", true)) {//true是实现第二次输入的时候能够拼接第一次的输入
//writer.write("666");
BufferedWriter bufferedWriter = new BufferedWriter(writer);//带缓冲区的流
bufferedWriter.write("777");//将内容写到缓冲区去里
bufferedWriter.flush();//将缓冲区里的内容写入文件
bufferedWriter.close();//可以放到try块里 自动关闭流
} catch (IOException e) {
e.printStackTrace();
}
}
}
* 缓冲区通常是一段内存的运行空间 提高编程效率 减少磁盘IO操作 但是在一些特殊情况下 如网络传输 数据库操作等 就需要使用非缓冲区的流 如FileWriter(false)
* 因此进行IO的时候就希望能使用缓冲区把要写的数据先放到缓冲区里 攒一波再一起写
* 或者读取的时候也不是一个一个的读 而是一次读取一批数据 放到缓冲区再慢慢解析
* 当前IO流 read和write就是属于直接读取文件了 想要提升效率
* 1.手动创建缓冲区 byte[]手动减少read和write的次数
* 2.就需要使用缓冲区流 如BufferedInputStream和BufferedOutputStream

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



