目录
初步了解计算机中的文件.
路径
文件的分类
一 . 文件系统操作
File 的相关操作
二 . 文件内容操作
字节流读操作
字符流操作
文件 : 在平时我们认为的文件就是指存储在硬盘上的普通文件.
比如说 : txt , jpg , rar 等等. 都是指硬盘上的文件.
而在计算机文件是一个广义的概念 , 不单是指普通文件 , 还包含了 目录(也就是我们理解文件夹) / 目录文件.
在操作系统中还用文件来描述一些其他的硬件设备或者软件资源. (例如网卡在操作系统也被抽象成一个文件 , 显示器/键盘 这些在操作系统中都视为文件)
硬盘 : 也称为外存 , 形如 : 固态硬盘 , 机械硬盘
内存 : 内存是外存 与 cpu 进行沟通的桥梁 , 内存的性能强弱影响着计算机整体运行的快慢.
从运行速度上来讲 : 硬存这个读写速度就比内存读写慢(3~4)个数量级 ,
固态硬盘(SSD) : 它比机械硬盘速度又要高很多 , 固态硬盘就像是一个大号的U盘(里面是flash芯片).
机械硬盘 : 里面存有磁盘 , 一通电 , 它就会高速的旋转 , 通过磁头来进行读写数据.
固态硬盘会比机械硬盘快上许多.
计算中目录是有层级结构的.
文件系统是以树型结构来组织文件和目录的. N叉树
文件的路径就是 : 从树的根节点出发 , 沿着线一直往下走 , 到达目标文件 , 经过的中间文件/目录组成起来就是路径. (一般把此电脑这个点省去 从盘符开始表示)
在操作系统中 , 就通过"路径" 来描述一个具体文件/目录的位置.
路径分为两种 :
2. 相对路径 : 首先想表示一个想相对路径就要有一个基准路径.
在文件系统中 , 任何一个文件的路径都是唯一的!!
绝不会存在路径相同 , 文件不同的情况!
在windows系统中 , 路径中使用 \ 来分割的. 但是我们在代码中经常使用 / 来分割 , 也可以通过 \\ 来作为分割符. 都是可以的. Windows都可以识别.
文件分为 : 文本文件 与 二进制文件
文本文件中存储的是字符 , (字符是由字节组成,本质上文本文件也是存字节的, 但是文本文件中, 相邻的字节在一起正好能构成一个个的字符). 文本文件的内容都是由ASCII 字符或者其他字符集编码构成的.
二进制文件中存储的是字节 (每个字节是没关联的).
在平常我们看到的 , .txt , .c , .java 都是文本文件
.rar , .doc , .ppt .class 都是二进制文件
区分是文本文件而是二进制文件的一个办法 : 通过记事本打开它 , 如果是乱码那么它就是二进制文件 , 否则就是文本文件.
文件系统操作包含创建文件 , 删除文件 , 重名文件 , 创建目录(文件夹) , 删除目录等等
Java 标准库, 给我们提供了File 类 .
File 对象就是硬盘上的文件的"抽象"表示 , 文件存储在硬盘上 , 通过操作的File 对象 , 就可以间接的影响到硬盘的文件情况了. File对象就像是一个遥控器. 通过操作遥控器我们就可以进行文件操作了.
构造一个File对象 , 可以通过相对路径/相对路径 进行初始化.
使用File 类需要 导入 java.io.File;
绝对路径 :
相对路径 : 在Idea中它的相对路径就是项目存在的位置.
import java.io.File;
import java.io.IOException;
public class Demo1 {
public static void main(String[] args) throws IOException {
// 创建一个File对象 使用了绝对路径
File file = new File("D:/test/EE");
// 返回File对象的父目录文件路径
System.out.println(file.getParent());
// 返回File对象的纯文件名
System.out.println(file.getName());
// 返回File 对象的文件路径
System.out.println(file.getPath());
// 返回 File 对象的绝对路径
System.out.println(file.getAbsolutePath());
// 返回File 对象的绝对路径
System.out.println(file.getCanonicalPath());
// 判断 File对象描述的文件是否真实存在
System.out.println(file.exists());
// 判断 File 对象所描述的文件是不是一个目录
System.out.println(file.isDirectory());
// 判断File 对象 所描述的文件是不是一个普通文件
System.out.println(file.isFile());
}
}
File file = new File("D:/test");
// 返回 File 对象代表的目录下的所有文件名
String[] strings = file.list();
System.out.println(Arrays.toString(strings));
// 返回 File 对象代表的目录下的所有文件
File[] files = file.listFiles();
System.out.println(Arrays.toString(files));
针对文件内容来进行读写操作.
1) 打开文件
2) 读文件
3) 写文件
4) 关闭文件
"流" Stream
这个流就像是我们平日里看到的水龙头 开关一样.
一开 , 它就开始流动 , 100ml的水 , 我们就可以分多次接 , 也可以一次性直接接完.一闭 , 它就停止流动
对应到流对象 , 对读取100个字节
也可以一次读10个字节 , 分10次接完
也可以一次读100个字节 , 一次读完.
...........................
对应到写, 也是一样.
对写100个字节
也可以一次写10个字节 , 分10次接完
也可以一次写100个字节 , 一次读完.
通过read 来读入文件中的字节
read 提供了三个版本的重载 :
将 1.txt 文件中的字符一个一个字节的全部读出.
import java.io.*;
import java.util.Arrays;
public class Demo1 {
public static void main(String[] args) {
try {
// 1. 创建对象 , 同时也是在打开文件
InputStream inputStream = new FileInputStream("D:\\test/1.txt");
// 2. 尝试一个一个字节的读 , 把整个文件都读完
while (true) {
int b = inputStream.read();
if (b == -1) {
// 如果读到文件的末尾 就返回一个 -1
break;
}
System.out.println(b);
}
// 3. 读完之后要记得关闭文件 , 释放资源
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
注意 : 使用完流对象后记得关闭 inputStream.close();
Java中有GC , 内存一般不用手动释放.
但是文件这里的资源 , 则需要手动释放!!
这个资源指的是"文件描述符"
进程, 是使用PCB 这样的结构来表示.包含了文件描述符表!
文件描述符表 : 记载了当前进程都打开了那些文件 , 每次打开一个文件, 就会在这个表里,申请到一个位置 , 把这个表想象成一个数组 , 但是这个表的长度是有限的!! 不能无休止的打开!
我们可以把close 操作放到 try (close操作) 系统会自动帮我们释放资源.
不然按照上面代码的写法 , 如果代码还没到执行到 关闭文件操作 , 报错了. 就不会执行到close操作.
只要实现了Closeable接口都可以按照这样的写法来释放资源.
import java.io.*;
public class Demo1 {
public static void main(String[] args) {
// 1. 创建对象 , 同时也是在打开文件
try (InputStream inputStream = new FileInputStream("D:\\test/1.txt")){
// 2. 尝试一个一个字节的读 , 把整个文件都读完
while (true) {
int b = inputStream.read();
if (b == -1) {
// 如果读到文件的末尾 就返回一个 -1
break;
}
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
一次读多个字节! 每次读磁盘是比较低效的操作, 能一次多读一点是更好的.
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class Demo2 {
public static void main(String[] args) {
try (InputStream inputStream = new FileInputStream("D:\\test/1.txt")){
byte[] bytes = new byte[1024];
while (true) {
int len = inputStream.read(bytes);
if (len == -1) {
break;
}
for (int i = 0; i < len; i++) {
System.out.println(bytes[i]);
}
// String s = new String(bytes,0,len,"utf8");
// System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
write 写操作
重点 : 每次按照写方式打开文件 , 都会清空原有文件的内容.清空旧的内容 , 再从起始位置往后写.
import java.io.*;
public class Demo3 {
public static void main(String[] args) {
try (OutputStream outputStream = new FileOutputStream("D:\\test/1.txt")) {
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
} catch (IOException e) {
e.printStackTrace();
}
}
}
一次写入多个字节!
import java.io.*;
public class Demo3 {
public static void main(String[] args) {
try (OutputStream outputStream = new FileOutputStream("D:\\test/1.txt")) {
byte[] bytes = new byte[]{65,66,67,68};
outputStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
一次读多个字符!
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class Demo4 {
public static void main(String[] args) {
try (Reader reader = new FileReader("D:\\test/1.txt")){
char[] buffer = new char[1024];
while (true) {
int len = reader.read(buffer);
if (len == -1) {
// 读到文件末尾
break;
}
// for (int i = 0; i < len; i++) {
// System.out.println(buffer[i]);
// }
String s = new String(buffer);
System.out.println(s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
一次写多个字符!
import java.io.*;
public class Demo5 {
public static void main(String[] args) {
try (Writer writer = new FileWriter("D:\\test/1.txt")){
char[] buffer = new char[]{97,'A',66,'里'};
writer.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
}