认识文件
狭义的文件
存储在硬盘上的数据,以“文件"为单位,进行组织
常见的就是普通的文件
(文本文件,图片, office系列,视频,音频可执行程序…)文件夹也叫做"目录"
也是一种特殊的文件。
广义的文件
操作系统,是要负责管理软硬件资源,操作系统(Linux)往往会把这些资源都统一的抽象成"文件"来进行管理。
“一切皆文件”
比如.有一个网卡就把网卡这个设备抽象成一个文件.创建了特殊的文件,表示网卡从网卡接受数据,就读这个文件,往网卡里发送数据,就写这个文件
比如,有一个键盘想从键盘读取数据,也是把键盘抽象成一个文件(stdin),,读这个文件就能读到用户输入的按键内容了.
目录结构
本质是一颗多叉树。
一个文件在电脑上的具体位置,就过多叉树上的路径来描述。
路径
1、绝对路径
从树型结构的角度来看,树中的每个结点都可以被一条从根开始,一直到达的结点的路径所描
述,而这种描述方式就被称为文件的绝对路径
E:\编程\xshell
2、相对路径
从根开始进行路径的描述,我们可以从任意结点出发,进行路径的描述,而这种描述方式就被
称为相对路径(relative path),相对于当前所在结点的一条路径
大白话:
首先得有一个"基准路径”也叫做"工作路径"
相对路径就是以基准路径为起点,往下继续怎么走,才能到达目标的路径表示方式
假设基准路径是E盘,此时我想到xshell这个目录下:E:\编程\xshell
./编程/xshell
.
用于表示"当前目录"
如果基准路径是:E:\编程\xshell\ColorSchemes
,我想到xshell目录找xshell.exe
用相对路径表示:…/xshell.exe
..
用于表示返回上一级目录
Java 中操作文件
文进程中是属于操作系统层面提供的一系列API,不同的操作系统提供的API不同,Java作为一个跨平台的语言,为了统一代码,就在JVM中把不同系统的操作文件的API进行了封装。
Java 中通过 java.io.File 类来对一个文件(包括目录)进行抽象的描述。注意,有 File 对象,并不
代表真实存在该文件。
File概述
看 File 类中的常见属性、构造方法和方法
构造方法:
签名 | 说明 |
---|---|
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 |
String[] | list() | 根据 File 对象,删除该文件。成功删除后返回 true |
File[] | listFiles() | 返回 File 对象代表的目录下的所有文件名 |
boolean | mkdir() | 创建 File 对象代表的目录 |
boolean | mkdirs() | 创建 File 对象代表的目录,如果必要,会创建中间目录 |
boolean | renameTo(File dest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操作 |
void | deleteOnExit() | 根据 File 对象,标注文件将被删除,删除动作会到JVM 运行结束时才会进行 |
实例代码1:
public static void main(String[] args) throws IOException {
File file = new File("E:\\编程\\coding");
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());
}
E:\编程 【父目录文件路径】
coding 【 FIle 对象的纯文件名称】
E:\编程\coding 【File 对象的文件路径】
E:\编程\coding 【返回 File 对象的绝对路径
E:\编程\coding 【返回 File 对象的修饰过的绝对路径】
实例代码2:
public static void main(String[] args) throws IOException {
File file = new File(".\\bbb.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());
}
. 【父目录文件路径】
bbb.txt 【 FIle 对象的纯文件名称】
.\bbb.txt 【File 对象的文件路径】
C:\Users\22479\Desktop\Java\源码项目包\File.\bbb.txt 【返回 File 对象的绝对路径】
C:\Users\22479\Desktop\Java\源码项目包\File\bbb.txt 【返回 File 对象的修饰过的绝对路径】
代码示例3:
【假设一开始没bbb.txt这个文件 当前的.代表的是
public static void main(String[] args) throws IOException {
File file = new File(".\\bbb.txt");
System.out.println(file.exists());
System.out.println(file.isDirectory());
System.out.println(file.createNewFile());
System.out.println(file);
}
false 【文件不存在】
false 【这不是一个文件夹文件】
true 【创建文件成功】
文件内容的读写**——** 数据流
【stream】流 :把读写操作比喻成“水流”
Java标准库就在“流”的概念上提供了一组类,完成读写文件的操作
InputStream概述
方法
返回类型 | 方法 | 说明 |
---|---|---|
int | read() | 读取一个字节的数据,未读取到返回-1 |
int | read(byte[] b) | 最多读取b.length字节的数据到b中,返回实际读到的数量。未读取到返回-1 |
int | read(byte[] b,int off,int len) | 从off位置开始,最多读取len个字节,返回实际读到的数量,未读到返回-1 |
void | close() | 关闭字节流 |
byte[] b:将读取到的内容放到这个数组中
InputStream 只是一个抽象类,要使用还需要具体的实现类,我们现在只关心从文件中读取,所以使用FileInputStream
FileInputStream
构造方法:
FileInputStream(File file) | 利用 File 构造文件输入流 |
---|---|
FileInputStream(String name) | 利用文件路径构造文件输入流 |
示例一:读取bbb.txt里面的内容
public static void main(String[] args) throws IOException {
//这个操作相当于打开文件,想要读文件就得先打开
InputStream inputStream = new FileInputStream(".\\bbb.txt");
while(true) {
int n = inputStream.read();
// 代表文件已经全部读完
if(n == -1) {
break;
}
System.out.println(n);
}
//打开完毕以后必须关闭,防止内存泄漏
inputStream.close();
}
读取的过程返回的int 值是对应字符的ascall码
当读完文件时候,read方法会返回-1
利用 Scanner 进行字符读取
上述例子中,我们看到了对字符类型直接使用 InputStream 进行读取是非常麻烦且困难的,所以,我们使用一种我们之前比较熟悉的类来完成该工作,就是 Scanner 类。
构造方法 | 说明 |
---|---|
Scanner(InputStream source) | 构造一个Scanner,产生从指定输入流产生的值 |
public static void main(String[] args) throws IOException {
//这个操作相当于打开文件,想要读文件就得先打开
InputStream inputStream = new FileInputStream(".\\bbb.txt");
//Scanner构造方法 产生从指定输入流产生的值
Scanner scanner = new Scanner(inputStream);
//hasnext() 去读,如果读到空字符串就结束
while(scanner.hasNext()) {
String n = scanner.next();
System.out.println(n);
}
//打开完毕以后必须关闭,防止内存泄漏
inputStream.close();
}
OutputStream 概述
OutputStream 同样只是一个抽象类,要使用还需要具体的实现类。我们现在还是只关心写入文件中,所以使用 FileOutputStream
返回值 | 方法 | 说明 |
---|---|---|
void | write(int b) | 写一个字节 |
void | write(byte[] bytes) | 将bytes数组的数据写到输出流 |
void | write(byte[] b,int off,int len) | 从off位置开始,写len长度的数据到输出流 |
void | close() | 关闭字节流 |
void | flush() | 刷新缓存区,将数据刷新到硬盘 |
flush():我们知道 I/O 的速度是很慢的,所以,大多的 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到该区域满了或者其他指定条件时才真正将数据写入设备中,这个区域一般称为缓冲区。但造成一个结果,就是我们写的数据,很可能会遗留一部分在缓冲区中。需要在最后或者合适的位置,调用 flush(刷新)操作,将数据刷到设备中。
FileOutputStream
构造方法 | 说明 |
---|---|
FileInOutStream(String name) | 利用文件路径构造文件输入流 |
向bbb.txt文件里面写入:“bili”
public static void main(String[] args) throws IOException {
//这个操作相当于打开文件,想要读文件就得先打开
OutputStream outputStream = new FileOutputStream(".\\bbb.txt");
//使用write往bbb.txt写内容
outputStream.write('b');
outputStream.write('i');
outputStream.write('l');
outputStream.write('i');
//关闭outputStream 防止内存泄漏
outputStream.close();
}
注意:使用OutputStream写文件的时候,只要打开文件成功,就会把原有的内容清空。
利用PrinterPrintWriter进行输出
PrintWriter 类中提供了我们熟悉的 print/println/printf 方法
public static void main(String[] args) throws IOException {
//这个操作相当于打开文件,想要读文件就得先打开
OutputStream outputStream = new FileOutputStream(".\\bbb.txt");
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.print('b');
printWriter.print('i');
printWriter.print('l');
printWriter.print('i');
printWriter.print('b');
printWriter.print('i');
printWriter.print('l');
printWriter.print('i');
//关闭outputStream 防止内存泄漏
printWriter.close();
outputStream.close();
}
Reader概述
读取的是字符类的数据流
返回类型 | 方法 | 说明 |
---|---|---|
int | read() | 读取一个字节的数据,未读取到返回-1 |
int | read(char[] b) | 最多读取b.length字节的数据到b中,返回实际读到的数量。未读取到返回-1 |
int | read(char[] b, int off, int len) | 从off位置开始,最多读取len个字节,返回实际读到的数量,未读到返回-1 |
Reader是一个接口,真正的想使用Reader下面的方法进行读取,还需要使用FileReader
FileReader
构造方法:
FileInputStream(File file) | 利用 File 构造文件输入流 |
---|---|
FileReader(String name) | 利用文件路径构造文件输入流 |
示例:
public static void main(String[] args) throws IOException {
//这个操作相当于打开文件,想要读文件就得先打开
Reader reader = new FileReader(".\\bbb.txt");
while(true) {
int n = reader.read();
if(n == -1) {
break;
}
//FileRed的read方法虽然返回值是int类型,当实际应该是字符类型,我们需要手动强转 【reader读取字符流】
System.out.print((char)n);
}
//进行问卷操作的时候完毕以后要close,防止资源泄露
reader.close();
}
为什么要close
每个进程都对应着(一个或者多个)PCB,PCB里面有一个字段,文件描述表。
文件描述表:相当于是一个数组/顺序表;进程每次打开 一个文件,都会在这个表里创建一个项,就表示一个文件,如果关闭一个文件,就会把对应的项释放掉。
如果不关闭,意味着这个项就在这里占着位置,如果你持续打开文件,并且从来不关,此时就会导致数组/顺序表位置被耗尽,后续再打开文件,就会打开失败。
这就称作:文件资源泄露,非常严重的问题。
例如一群人来图书馆,每次借书以后都不还,后面的人想要借也没了,被那群不还的家伙借光了。
try with resources
解决办法:使用try with resource
把要关闭的对象写到try()里,当try结束,就会自动的调用到对应的对象的close方法,而且支持一个()放多个对象,多个对象的创建之间使用;
分割就行了。
OuptString操作每次都会覆盖之前的文件内容
/顺序表位置被耗尽,后续再打开文件,就会打开失败**。
这就称作:文件资源泄露,非常严重的问题。
例如一群人来图书馆,每次借书以后都不还,后面的人想要借也没了,被那群不还的家伙借光了。
try with resources
[外链图片转存中…(img-ZZivm3gg-1678103137099)]
解决办法:使用try with resource
[外链图片转存中…(img-1PIV7pLS-1678103137100)]
把要关闭的对象写到try()里,当try结束,就会自动的调用到对应的对象的close方法,而且支持一个()放多个对象,多个对象的创建之间使用;
分割就行了。
OuptString操作每次都会覆盖之前的文件内容
FileRed的read方法虽然返回值是-1,但是他的真正的返回值其实是一个