文件系统及Java文件基本操作
- 文件系统是由OS管理的
- 文件系统和 Java进程是并行的
- 文件系统分隔符:Linux/Unix 用 / 隔开
- 文件系统分隔符:Windows 用 \ 隔开,涉及到转义,在程序中需要用 / 或者 \
- 文件包括文件里面的内容和文件基本属性
- 文件基本属性有:名称、大小、扩展名、修改时间等
Java文件类File
java.io.File 是文件和目录的重要类(JDK6之前是唯一类)
创建对象的方法:
- new FIle(String pathName)
- new FIle(File parent, String childName) // 父目录文件 + 子路径
- new FIle(String parent, String childName) // 父路径 + 子路径
例子:
@Test
public void created01() {
String filepath = "C:\\Users\\acer\\Desktop\\fileTest.txt";
// 在内存中创建文件对象
File file = new File(filepath);
try {
// 在磁盘上创建该对象对应的文件
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void created02() {
File parentFile = new File("C:\\Users\\acer\\Desktop");
String child = "fileTest666.txt";
File file = new File(parentFile, child);
try {
file.createNewFile();
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
File类与OS无关,但是会受到OS的权限限制
常用方法:
- createNewFile
- delete
- exists
- getAbsolutePath
- getName
- getParent
- getPath
- isDirectory
- isFile
- length
- listFiles
- nkdir
- mkdirs
注意,File不涉及具体的文件内容,只涉及属性
在 Java 中,目录也被认为是文件
public static void main(String[] args) {
// 创建目录
File d = new File("c:/temp");
if (!d.exists()) {
d.mkdir();
}
System.out.println("Is f directort? " + d.isDirectory());;
// 创建文件
File f = new File("C:/temp/abc.txt");
if(!f.exists()) {
try {
f.createNewFile();
}
catch (IOException e) {
e.printStackTrace();
}
}
// 输出文件相关属性
System.out.println("Is f file? " + f.isFile());
System.out.println("Name: " + f.getName());
System.out.println("Parent: " + f.getParent());
System.out.println("Path: " + f.getPath());
System.out.println("Last modified time: " + f.lastModified() + "ms");
// 遍历d目录下所有的文件信息
System.out.println("list files in d directory");
File[] fs = d.listFiles();
for (File f1:fs) {
System.out.println(f1.getPath());
}
// 关闭文件,释放内存
f.delete();
d.delete();
}
NIO
Java7 提出的NIO包,提出新的文件系统类
- Path,Files,DirectoryStream,FileVisitor,FileSystem
- 是 java.io.file 的有益补充:文件复制和移动、文件相对路径、递归遍历/删除目录
例子:
public static void main(String[] args) {
// Path 和 java.io.file 基本一样
// 获得path的方法一
Path path = FileSystems.getDefault().getPath("c:/temp", "abc.txt");
System.out.println(path.getNameCount()); // 2
// 获得path的方法二
File file = new File("c:/temp/abc.txt");
Path path2 = file.toPath();
System.out.println(path.compareTo(path2));; // 0,说明相等
// 方法三
Path path3 = Paths.get("c:/temp", "abc.txt");
System.out.println(path3.toString());
// 方法四
Path path4 = Paths.get("c:/temp");
System.out.println("path4: " + path4.resolve("abc.txt"));
if(Files.isReadable(path)) {
System.out.println("66666");
}
else {
System.out.println("555555");
}
}
输出结果:
2
0
c:\temp\abc.txt
path4: c:\temp\abc.txt
66666
例子2:
public static void main(String[] args) {
moveFile();
fileAttributes();
createDirectory();
}
public static void moveFile() {
Path from = Paths.get("c:/temp", "abc.txt");
// 移动文件到c:/temp/test/def.txt,若存在则替换
Path to = from.getParent().resolve("test/def.txt");
try {
// 文件的大小bytes
System.out.println(Files.size(from));
// 调用文件移动方法,若存在则替换
Files.move(from, to, StandardCopyOption.REPLACE_EXISTING);
}
catch (IOException e) {
System.out.println("移动文件错误");
e.printStackTrace();
}
}
public static void fileAttributes() {
Path path = Paths.get("c:/temp");
// 1
System.out.println(Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS));
// 2
try {
// 获取文件的基础属性
BasicFileAttributes attributes = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println(attributes.isDirectory());
System.out.println(new Date(attributes.lastModifiedTime().toMillis()));
}
catch (IOException e) {
e.printStackTrace();
}
}
public static void createDirectory() {
Path path = Paths.get("c:/temp/test");
try {
// 创建文件夹
if (Files.notExists(path)) {
Files.createDirectories(path);
System.out.println("create Dir");
}
else {
System.out.println("dir exists");
}
Path path2 = path.resolve("A.java");
Path path3 = path.resolve("B.java");
Path path4 = path.resolve("C.jpg");
Path path5 = path.resolve("D.txt");
Files.createFile(path2);
Files.createFile(path3);
Files.createFile(path4);
Files.createFile(path5);
// 不加条件遍历
DirectoryStream<Path> paths = Files.newDirectoryStream(path);
for (Path p : paths) {
System.out.println(p.getFileName());
}
System.out.println();
// 创建一个带有过滤器,过滤文件名以java.txt结尾的文件
DirectoryStream<Path> pathsFilter = Files.newDirectoryStream(path, "*.{java,txt}");
for(Path p : pathsFilter) {
System.out.println(p.getFileName());
}
}
catch (IOException e) {
e.printStackTrace();
}
}
输出结果:
0
true
true
Mon Aug 23 20:56:44 CST 2021
dir exists
A.java
B.java
C.jpg
D.txt
def.txt
A.java
B.java
D.txt
def.txt
小结
- 文件系统和Java是并列的两套系统
- File类是文件基本操作的主要类
- Java 7 提出的NIO包在某些功能上有重要的补充
Java io 包概述
Java读写文件,只能以数据流的形式进行读写。因为文件可能很大,不能一次性全部读进内存,只能以流的形式分批读取。
java.io包中:
- 节点类:直接对文件进行读写
- 包装类:又分为转化类(字节/字符/数据类型的转化类)和装饰类(装饰节点类)
节点类
- InputStream, OutputStream(字节)用来处理文件
- Reader,Writer(字符)用来处理字符
转化类
字节到字符的转化
- InputStreamReader:文件读取时,将读进来的字节转化为Java能理解的字符
- OutputStreamWriter:Java将字节转化为字符输入到文件中
装饰类
装饰节点类
- DataInputStream, DataOutputStream:封装数据流
- BufferedInputStream, BufferedOutputStream:缓存字节流
- BufferedReader, BufferedWriter:缓存字符流
思维导图(截图自Mooc中 华东师范大学 课程《Java核心技术》)
文本文件读写
文件类型:
- 一般文本文件(若干行字符构成的文件),如txt
- 一般二进制文件,如dat
- 带特殊格式的文本文件,如xml
- 带特殊格式的二进制文件,如doc, ppt
文件是数据的一个容器,用来存放大量的数据。
文件很大,Java只能以流的方式读入。
写文件
- 先创建文件,写入数据,关闭文件
- 用到三个类 FileOutputStream(文件中写字节), OutputStreamWriter(字节和字符转化), BufferedWriter(加速写操作)
- BufferWriter: write / newLine
- try-resource 语句,自动关闭资源(JDK7 以上才有)
- 关闭最外层的数据流,即会关闭上述三种数据流
例子:
public static void main(String[] args) {
writeFile1();
System.out.println("++++++++++++++++++++++++");
wirteFile2();
}
public static void writeFile1() {
FileOutputStream fos = null;
OutputStreamWriter osw = null;
BufferedWriter bw = null;
try {
// 节点类,负责写字节
fos = new FileOutputStream("c:/temp/abc.txt");
// 转化类,负责字符到字节的转化
osw = new OutputStreamWriter(fos, "UTF-8");
// osw = new OutputStreamWriter(fos);
// 装饰类,负责写字符到缓冲区
bw = new BufferedWriter(osw);
bw.write("我们是");
bw.newLine();
bw.write("ucaser.^^");
bw.newLine();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
// bw 为最外层的类(其装饰了osw,而osw转化了fos),只关闭最外层即可
bw.close();
}
catch (Exception e){
e.printStackTrace();
}
}
}
public static void wirteFile2() {
// try-resource, 自动关闭资源
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("c:/temp/abc.txt")))) {
bw.write("我们是");
bw.newLine();
bw.write("ucaser.^^");
bw.newLine();
}
catch (Exception e) {
e.printStackTrace();
}
}
读文件
- 先打开文件,逐行读入数据,关闭文件
- 三个类:FileInputStream, InputStreamWriter, BufferedReader
- BufferReader: readLine
- try-resource 语句,自动关闭资源
- 关闭最外层的数据流,即会关闭上述三种数据流
例子:
public static void main(String[] args) {
readFile1();
System.out.println("=======================");
readFile2();
}
public static void readFile1() {
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
try {
// 节点类,读入字节数据
fis = new FileInputStream("c:/temp/abc.txt");
// 字符类,字节数据转化为字符
isr = new InputStreamReader(fis, "UTF-8");
// 装饰类,将读入数据装入缓存
br = new BufferedReader(isr);
String line;
// 每次读取一行,直至空行
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
// bw 为最外层的类(其装饰了osw,而osw转化了fos),只关闭最外层即可
br.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
public static void readFile2() {
String line;
// try-resource
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("c:/temp/abc.txt")))) {
// 每次读取一行,直至空行
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
catch (Exception e) {
e.printStackTrace();
}
}
小结
- 理解节点类、转换类和装饰类的联合用法
- 尽量使用try-resource语句,自动关闭资源
二进制文件读写
二进制文件
- 狭义上说,采用字节编码,非字符编码的文件
- 广义上讲,一切文件都是二进制文件(因为磁盘只能保存二进制)
- 用记事本无法打开/阅读
写文件
- 先创建文件,写入数据,关闭文件
- 三个类:FileOutputStream, BufferedOutputSteam, DataOutputStream
- DataOutputStream: flush; write/writeBoolean/writeByte/writeChars/writeDouble/writeInt/…
- try-resource 语句,自动关闭资源
- 关闭最外层的数据流,即会关闭上述三种数据流
例子:
public static void main(String[] args) {
writeFile();
System.out.println("6666666666666666666");
}
public static void writeFile() {
FileOutputStream fos = null;
DataOutputStream dos = null;
BufferedOutputStream bos = null;
try {
// 节点类
fos = new FileOutputStream("c:/temp/def.dat");
// 装饰类
bos = new BufferedOutputStream(fos);
// 装饰类
dos = new DataOutputStream(bos);
dos.writeUTF("a");
dos.writeInt(20);
dos.writeShort(120);
dos.writeUTF("p");
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
dos.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
读文件
- 先打开文件,读入数据,关闭文件
- FileInputStream, BufferedInputStream, DataInputStream
- DataInputStream: read/readBoolean/…
- try-resource 语句,自动关闭资源
- 关闭最外层的数据流,即会关闭上述三种数据流
例子:
public static void main(String[] args) {
readFile();
}
public static void readFile() {
// try-resource
try (DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("c:/temp/def.dat")))) {
String a, b;
int c;
short d;
a = dis.readUTF();
c = dis.readInt();
d = dis.readShort();
b = dis.readUTF();
System.out.println("a:" + a);
System.out.println("c:" + c);
System.out.println("d:" + d);
System.out.println("b:" + b);
}
catch (Exception e) {
e.printStackTrace();
}
}
小结:
- 理解节点类、转化类和包装类的联合用法
- 读取时需要按照写入的规则进行读取, 避免错位
- 尽量使用try-resource