文件操作和IO
文件概述
1、文件的基本认识
计算机上的所有文件可以简单地分成文本文件和二进制文件。比如常用的记事本(.txt)就是文本文件,它存储的是有意义的一个一个的字符。又比如可执行程序(.exe)存储的就是二进制文件,存储的是0和1。
另外文件除了有数据内容外,还有其他的一些信息,比如文件名、文件类型、创建日期、内存大小等。
这些用来修饰文件的信息,称为文件的元信息。
2、文件组织管理
当文件较多的时候,需要想办法,组织管理这些文件。这里最好的办法就是我们在数据结构中学过的,树形结构。
比如这个src文件:
底层使用的就是一个N叉树:
3、文件路径
文件路径分为绝对路径和相对路径。
举一个形象的例子描述:
比如我要去女神家玩。那么我可以有两个方式告诉司机他要怎么走。
第一种:从国家,到省,再到市,然后…… 最后,精确到门牌号。(绝对路径,这种行为有点不正常)
第二种:以一个地方为基准,比如从我家开始,出门沿着华阳路南,到XX站,然后经过XX路口,左转到她家门口。(相对路径,这种方式很常用)
具体到计算机中的文件:
“D:\下载的地方\组织结构图.png”——绝对路径
假设在"D:\下载的地方"操作文件(以"D:\下载的地方“为基准路径):
" .\组织结构图.png "——相对路径
注意
- 绝对路径在不同的计算机上,可能不同,因为每个人存储数据的路径不是一样的,因此大部分时候使用的都是相对路径。
- 相对路径必须要有一个基准路径,基准路径+相对路径就可以找到文件(就等于本地的绝对路径)。
- 在IDEA中操作文件,默认基准路径是项目的路径。
- “ ./XXX” 的含义是当前目录下的XXX文件或者目录。
JAVA中操作文件
1、File
File类可以传入一个文件的路径或者目录的路径(绝对路径/相对路径都可以),为其构造一个实例对象,常用的方法如下:
注意
- getPath()获取的是File类构造方法所填写的路径
- 获取修饰过的路径意思是会把“./”这种表示当前路径的修饰符省略掉,获取一个直观的绝对路径。
2、InputStream与OutputStream(比特流)
注意这里的Input(读入)和Output(写出)都是以CPU的视角来看的!
Input意思就是从缓存加载数据到CPU。
Output就是把CPU中的数据写入到缓存中。
InputStream
方法:
说明
- InputStream是一个抽象类,需要具体的类来实现,关于具体的实现类有很多,可以认为不同的输入设备都有一个对应的InputStream类,这里因为是文件操作,所以就介绍FileInputStream。
- FileInputStream构造方法:
示例:
// 需要先在项⽬⽬录下准备好⼀个 hello.txt 的⽂件,⾥⾯填充 "Hello" 的内容
public class CSDN {
public static void main(String[] args) throws IOException {
//try(){}是一个新型的语法,它可以自动进行close!!!
//try()括号内,填入IO类,可以填入多个,但是要用分号隔开!!
try (InputStream is = new FileInputStream("hello.txt")) {
while (true) {
int b = is.read();//这个版本读取一个字节
if (b == -1) {
// 代表⽂件已经全部读完
break;
}
System.out.printf("%c", b);
}
}
}
}
OutputStream
方法
修饰符及返回值类型 | 方法签名 | 说明 |
---|---|---|
void | write(int b) | 写入要给字节的数据 |
void | write(byte[] b) | 将 b 这个字节数组中的数据全部写入 os 中 |
int | write(byte[] b, int off, int len) | 将 b 这个字节数组中从 off 开始的数据写入 os 中,一共写 len 个 |
void | close() | 关闭字节流 |
void | flush() | 重要:我们知道 I/O 的速度是很慢的,所以,大多数 OutputStream 为了减少设备操作的次数,在写数据的时候都会将数据先暂时写入内存的一个指定区域里,直到这个区域满了或者其他条件使得它们才真正将数据写入设备中。这个区域一般称为缓冲区。但总有一个结果,就是我们写的数据,很可能会滞留在缓冲区。需要在最后或者合适的时机,调用 flush(刷新)操作,将数据刷到设备中。 |
示例:
public class CSDN {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
byte[] b = new byte[] {
(byte)'G', (byte)'o', (byte)'o', (byte)'d', (byte)'B', (byte)'a'
};
os.write(b, 0, 4);
}
}
}
3、Reader与Writer(字符流)
Reader和Writer也是抽象类。
它们的实现类有很多,其中就含有FileReader和FileWriter。
Reader和Writer在功能上和InputStream和OutputStream是一样的,只是前者是字符流,后者是比特流。
也就是读取和写入的数据类型有差别,仅此而已,所以这里就不过多介绍了。
具体方法仍然是参考上面的比特流。
Writer示例:
创建一个test.txt文本文件,然后在里面写入数据:
public class Demo8 {
public static void main(String[] args) throws IOException {
//在当前目录先创建一个test.txt文件
File file=new File("./test.txt");
if(!file.exists())file.createNewFile();
//开始写入数据,第二个参数名字叫append,如果为true,
//那么test.txt中原先是有内容的,那么会在原先内容的基础上进行添加数据!!!
Writer writer=new FileWriter("./test.txt",true);
writer.write("在这里写入一些内容,进行测试");
writer.close();
}
}
Reader示例:
从test.txt中读取内容,然后打印出来:
public class Demo8 {
public static void main(String[] args) {
try(Reader reader=new FileReader("./test.txt")){
while(true){
char[] buffer=new char[1024];//字符流
int n=reader.read(buffer);//把读到的内容放到字符数组中
if(n==-1)break;//如果读取失败,或者已经读完,就返回-1,所以直接退出循环
for (int i = 0; i < n; i++) {
System.out.print(buffer[i]);
}
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行结果: