一 认识文件
1.1 文件路径
文件路径就是描述一个文件在文件系统中的唯一标识,文件路径分为绝对路径和相对路径。绝对路径:从文件系统根目录开始定位某文件的具体位置的一个路线就是绝对路径。相对路径:以当前所在目录路径为基准,定位目标文件的路线。
1.2 文本文件与二进制文件
二 Java中操作文件
2.1 File类概述
File类可认为是对文件(目录也是文件)的属性信息进行一些操作。
2.1.1 File类的构造函数
函数 | 说明 |
File(File parent, String child)
|
根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实例
|
File(String pathname)
|
根据⽂件路径创建⼀个新的 File 实例,路径可以是绝 对路径或者相对路径
|
File(String parent, String child)
|
根据⽗⽬录 + 孩⼦⽂件路径,创建⼀个新的 File 实 例,⽗⽬录⽤路径表⽰
|
最常用的是第二种,简单明了。
2.1.2 File类提供的方法
修饰符及返回值类型
| 函数 | 说明 |
String
|
getParent()
|
返回 File 对象的⽗⽬录⽂件路径
|
String
|
getName()
|
返回 FIle 对象的纯⽂件名称
|
String
|
getPath()
|
返回 File 对象的⽂件路径
|
String
|
getAbsolutePath()
|
返回 File 对象的绝对路径
|
boolean
|
exists()
|
判断 File 对象描述的⽂件是否真实 存在
|
boolean
|
isDirectory()
|
判断 File 对象代表的⽂件是否是⼀
个⽬录
|
boolean
|
isFile()
|
判断 File 对象代表的⽂件是否是⼀
个普通⽂件
|
String[]
|
list()
| 返回File对象代表的目录下所有的文件名 |
File[]
|
listFiles()
|
返回 File 对象代表的⽬录下的所有
⽂件,以 File 对象表⽰
|
import java.io.File;
public class dirio {
public static void main(String[] args) {
File file = new File("D:/test.txt");
System.out.println(file.getName());
System.out.println(file.getPath());
System.out.println(file.getAbsolutePath());
System.out.println(file.isFile());
System.out.println(file.isDirectory());
}
}
以上的函数并不是File类中的所有函数。这些方法都是JVM封装操作系统提供的API实现的。JVM是由C++实现的, 对于所有系统下,比如:Windows,Linux,都是统一的。都是使用这一套函数,因为JVM做了封装。程序员在使用时不用考虑兼容问题。
三 文件内容的读写⸺数据流
Java中通过“流”这样的一组类进行对文件内容的操作,文件读写像流水一样。“流”分为两种,字节流和字符流。字节流是以字节为基本单位读写数据,有InputStream,OutputStream。字符流是以字符为基本单位读写数据,有Reader,Writer。
3.1 InputStreamのFileInputStream读取数据
查看InputStream可知,InputStream类被abstract修饰,证明这是一个抽象类,想使用它要自己定义类重写抽象方法。标准库中,已经实现了InputStream的的子类,不仅仅有对磁盘文件的读取的子类,也有从网卡读取的子类(PipedInputStream
)等等。标准库实现对磁盘文件读取的子类是FileInputStream。
使用方法很简单,1)调用构造函数创建FileInputStream对象 2)调用FileInputStream类实现的函数完成读取操作
FileInputStream的构造函数有两种。
FileInputStream会抛受查异常(编译时异常)FileNotFoundException, FileNotFoundException 是 Java 中的一个异常,表示试图打开一个不存在的文件或路径。它是 IOException的子类。
IOException
是 Java 中的一个异常类,表示在进行输入输出操作失败或被中断。它是所有输入输出异常的父类。
接下来调用FileInputStream的read方法,即可读取对应文件的数据。read方法有三种格式。
3.1.1 read无参版本
1)第一种无参版本,每次只读一个字节,读取到的内容通过返回值返回,如果读取不到返回-1,返回值不用byte而是用int,是因为byte范围是从-128-127,如果读取失败,无法通过返回值告知。所以采用了int。
import java.io.*;
public class dirio {
public static void main(String[] args) throws IOException {
File file = new File("D:/test.txt");
FileInputStream fileInputStream = new FileInputStream("D:/test.txt");
while (true) {
int res = fileInputStream.read();
if (res == -1)
break;
System.out.printf("%c", res);
}
}
}
为什么不用short而是用int,使用short不是可以省下2个字节吗?
short和float是上个世纪80,90时代使用的,那时候还是采用的16位CPU,内存紧张。如今硬件设备发展迅速,已经不在乎2个字节的消耗,而且就算使用short,如今使用的32位CPU也会将short整形提升为int。float精度太低,容易造成误差,所以更不用了。
3.1.2 read单参数版本
read(byte[ ]),byte[ ]是一个输出型参数。对,就是C++中的那个输出型参数,这种方式在C++中是很常用的,但是在Java中是不常用的。读取到的结果回被存储在传进去的byte数组中。返回值是实际读取到了多少个字节。
import java.io.*;
public class dirio {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("D:/test.txt")) {
byte[] buf = new byte[1024];
int len = 0;
while(true) {
len = is.read(buf);
if (len == -1) {
// 代表⽂件已经全部读完
break;
}
for (int i = 0; i < len; i++) {
System.out.printf("%c", buf[i]);
}
}
}
}
}
3.1.3 read三参数版本
read(byte[ ],int off,int len) 从off下标开始读取len个长度字节存储在byte数组中。
3.2 关闭文件
使用FileInputStream读取文件,在操作系统中,其实是会在进程PCB的文件描述符表中的数组中占一个位置,这个数组的长度是有一定限度的,如果这个数组被占满了再打开文件就放不下了,这个进程就崩溃了,服务器是7×24小时运行的,所以不能崩,要及时手动关闭打开的文件,避免文件资源泄露。在Linux上,ulimit -n可以查看这个数组的大小。如果怕忘记了,可以借助try语句。try with resources。在try后面跟一个圆括号,资源会在 try
块结束后自动关闭,减少了代码中的冗余。
import java.io.*;
public class dirio {
public static void main(String[] args) throws IOException {
try (InputStream is = new FileInputStream("D:/test.txt")) {
,,,,,,
}
}
}
3.3 OutputStreamのFileOutputStream写入数据
注意:在构造时候,默认是清空内容再写入,如果想追加,则构造时候,加一个true。
3.3.1 write无参版本
一次写入一个字节,它的参数类型是int。在 Java 中,int
的范围是 -2,147,483,648 到 2,147,483,647,而字节的范围是 0 到 255。将一个字节(0-255)转换为int,可以用int 表示这个字节的值,方便地进行位运算。如果直接使用 byte
类型作为参数,可能会引起一些混淆,因为 byte
是有符号的(-128 到 127)。通过使用 int
,你可以在方法内部更容易地处理和转换数据。
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("output.txt")) {
os.write('H');
os.write('e');
os.write('l');
os.write('l');
os.write('o');
}
}
}
3.3.2 write单参数byte数组
import java.io.*;
public class dirio {
public static void main(String[] args) throws IOException {
try(FileOutputStream os = new FileOutputStream("D:/test.txt",true)) {
byte[] b = new byte[] { 'G', 'o', 'o', 'd' };
os.write(b);
}
}
}
3.3.3 write三参数版本
import java.io.*;
public class dirio {
public static void main(String[] args) throws IOException {
try (OutputStream os = new FileOutputStream("D:/test.txt")) {
byte[] b = new byte[] {'G','o', 'o','d','B','a'};
os.write(b, 0, 4);
}
}
}
三 总结
文件IO类还有很多,使用方法大同小异。基本都是有一个父类,再根据不同的场景封装不同的系统调用。对于文件IO基本就有三步1)打开文件(构造) 2)读写 3)关闭文件