Java 文件IO
一、什么是文件IO
文件是一个广义的概念,操作系统将很多资源都抽象成文件,这篇文章讲解文件特指硬盘上的文件
在硬盘上存在很多文件和目录,它们以一种N叉树的结构存储
注意:文件夹也是一种文件,它是一种目录文件
二、路径
为了能定位到某个具体文件,需要引入路径,路径就是从根节点为起点,经过一些目录最终到达目标文件的"集合";路径分为绝对路径和相对路径
1)绝对路径:
以盘符为开头的路径称为绝对路径,如:D:/program/qq/Bin/qq.exe
2)相对路径:
相对路径的起点可以是任意路径
这个是qq.exe的绝对路径:D:/program/qq/Bin/qq.exe
假如当前的基准是D:/program/qq/Bin,那相对路径可以写成:. /qq.exe(. 表示当前位置)
当前基准是D:/program/qq,相对路径可以写成:./Bin/qq.exe
当前基准是D:/program/qq/Bin/plugins,相对路径可以写成:. . /qq.exe(..表示返回上一级目录)
三、文件的分类
文件的分类有很多种,这里讲解一种和编写代码密切相关的:文本文件 vs 二进制文件
将文件从记事本打开:
左侧:文本文件;右侧:乱码→二进制文件
文本文件是给人看的,二进制文件是给程序看的
四、使用Java操作文件
1)针对文件系统操作,如:创建文件、删除文件、重命名文件、创建目录等
2)针对文件内容操作,如:读文件、写文件
4.1 针对文件系统
Java标准库提供了 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对象的修饰过的绝对路径 |
方法演示:
File file = new File("./test.txt"); //.代表当前项目的路径
System.out.println("file.getParent(): "+ file.getParent());
System.out.println("file.getName(): "+ file.getName());
System.out.println("file.getPath() :"+ file.getPath());
System.out.println("file.getAbsolutePath(): "+ file.getAbsolutePath());
System.out.println("file.getCanonicalPath(): "+ file.getCanonicalPath());
结果演示:
方法 | 描述 |
boolean exists() | 判断File对象描述的⽂件是否真实存在 |
boolean isDirectory() | 判断File对象代表的⽂件是否是⼀个⽬录 |
boolean isFile() | 判断File对象代表的⽂件是否是⼀个普通⽂件 |
boolean createNewFile() | 根据File对象,⾃动创建⼀个空⽂件。成功创建后返回true |
方法演示:
File file = new File("./test.txt");
// 此时还没有创建文件, file只是一个File实例
System.out.println(file.exists()); //false
System.out.println(file.isFile()); //false
System.out.println(file.isDirectory()); //false
File file = new File("./test.txt");
// 此时创建了文件
file.createNewFile();
System.out.println(file.exists()); //true
System.out.println(file.isFile()); //true
System.out.println(file.isDirectory()); //false
方法 | 描述 |
boolean delete() | 根据File对象,删除该⽂件。成功删除后返回true |
void deleteOnExit() | 根据File对象,标注⽂件将被删除,删除动作会到JVM运⾏结束时(进程结束)才会进行 |
String[] list() | 返回File对象代表的⽬录下的所有⽂件名 |
File[] listFiles() | 返回File对象代表的⽬录下的所有⽂件,以File对象表⽰ |
boolean mkdir() | 创建File对象代表的⽬录,只能创建一级目录 |
boolean mkdirs() | 创建File对象代表的⽬录,可以创建多级目录 |
public static void main(String[] args) {
File f = new File("./testDir");
f.mkdir();
System.out.println(f.isDirectory());
}
方法 | 描述 |
boolean renameTo(File dest) | 进行文件改名,也可以视为我们平时的剪切、粘贴操作 |
boolean canRead() | 判断用户是否对⽂件有可读权限 |
boolean canWrite() | 判断用户是否对⽂件有可写权限 |
public static void main(String[] args) {
File f = new File("./testDir/test2.txt");
File file = new File("./test.txt");
file.renameTo(f); //将原本路径下的文件修改为新路径下的新名字的文件
}
4.2 针对文件内容
Java中通过流这样的一组类,进行文件内容的操作
字节流:以字节为单位读写数据(二进制文件) → InputStream、OutPutStream
字符流:以字符为单位读写数据(文本文件)→ Reader、Writer
4.2.1 InputStream
InputStream是一个抽象类,不能实例化,但标准库已经提供好了子类
InputStream inputStream = new FileInputStream("./testDir/test2.txt");
这里构造方法填写参数:
- 填写字符串表示的文件路径(绝对/相对均可)
- 填写File对象
这行代码就会通过构造方法打开一个文件,如果打开文件成功,就可以进行后续读取操作了
1)int read()
一次读取一个字节,将读取到的内容返回
此处一次读取一个字节,为什么返回值类型不是byte,而是int:
read()方法,如果返回值类型是byte,byte的取值范围为-128到127,但是需要一种机制表示输入流结束,这里通过返回-1表示流结束,但是-1在-128到127属于有效值,所以要改为int扩大取值范围,让0到255表示有效值,-1表示流结束
代码案例:
事先在test2.txt里面写上hello
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("./testDir/test2.txt");
while (true) {
int b = inputStream.read();
if (b == -1) {
break;
}
System.out.printf("0x%x ", b);
}
}
将16进制转化为10进制,正好对应ASCIIdh、e、l、l、o
2)int read ( byte[ ] b )
将读到的数据填写到byte数组中,返回值代表实际读取了多少个字节,返回-1代表读完了
代码案例:
public static void main(String[] args) throws IOException {
InputStream inputStream = new FileInputStream("./testDir/test2.txt");
while (true) {
byte[] b = new byte[1024];
int n = inputStream.read(b);
if (n == -1) {
break;
}
for (int i = 0; i < n; i++) {
System.out.printf("0x%x ", b[i]);
}
}
}
每次读完都会将数据存放在b中,如果文件数据过多,每次读取都会填满数组,然后循环多次
3)int read ( byte[ ] b, int off, int len )
读取文件中数据并填充数组的一部分,从 offset 开始,填充 len 这么长
4.2.2 关闭文件
打开文件的时候,操作系统内核会向该进程中的PCB结构体中,给文件描述符表里添加一个元素,这个元素表示当前打开的文件的各种信息(文件描述符表相当于一个顺序表,但不能扩容),当使用close关闭文件时,文件描述符表里对应的元素就会被释放掉
如果文件只开不关,文件描述符表就会被占满,一旦占满,再次打开文件,就会打开失败
我们刚刚写的程序,没有关闭文件好像没什么问题,这是因为代码很快就执行完了,进程也就结束了,进程一结束,pcb就会被释放掉,就没有什么机会将文件描述表占满,
打开文件和关闭文件之间会有一系列的操作,有的操作可能会return或抛出异常,导致文件没有及时关闭,和之前ReentrantLock类似:将解锁操作写到finally里;这里关闭文件也可以写到finally里
除此之外还有一种方法:try with resource
将流对象的创建写到 try ( ) 中,代码执行出了 try { } 后,就会自动调用关闭文件的操作,注意,写进 try ( ) 中的流对象的类必须实现了 Closeable 接口
try (InputStream inputStream = new FileInputStream("D:/test.txt")) {
byte[] b = new byte[1024];
int n = inputStream.read(b);
for (int i = 0; i < n; i++) {
System.out.printf("0x%x ", b[n]);
}
}
4.2.3 OutputStream
方法 | 描述 |
void write ( int b ) | 一次写一个字节 |
void write ( byte[ ] b ) | 一次写若干个字节,把数组b里的所有字节都写入文件中 |
void write ( byte[ ] b, int off, int len ) | 一次写若干个字节,从b数组的off下标开始写,写len个字节 |
//OutputStream 为抽象类,使用子类 FileOutputStream 实例化
OutputStream out = new FileOutputStream("./testDir/test2.txt");
//连续写3个 a
out.write(97);
out.write(97);
out.write(97);
按照写方式打开文件时,会把文件原有的内容清空(不是write清空的,而是打开文件时清空的)可以使用追加写
新数据会在原数据的末尾:
4.2.4 Reader
方法 | 描述 |
int read ( ) | 一次读取一个字符,返回-1表示读取结束 |
int read ( char[ ] cbuf ) | 读取若干个字符到cbuf数组中,返回-1表示读取结束 |
事先在test2.txt中写上:你好世界
public static void main(String[] args) {
//Reader为抽象类,使用子类 FileReader 实例化
try (Reader reader = new FileReader("./testDir/test2.txt")) {
while (true) {
int b = reader.read(); //一次读取一个字符
if (b == -1) {
break;
}
char ch = (char)b;
System.out.println(ch);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
- 问题:读出来的内容是中文,一个中文字符占3个字节,但Java中char类型占2个字节,为什么可以读取成功?
- 答:虽然文件中原始数据是3个字节一个字符,read操作读取的时候,能够识别文件是utf-8格式,读的是3个字节,返回成一个char的时候,会将utf-8转成unicode,这样一个字符就占2个字节
4.2.5 Writer
方法 | 描述 |
void write( int c ) | 一次写一个字符 |
void write( char[ ] cbuf ) | 将数组 cbuf 中的字符写入文件 |
void write( String str ) | 将字符串 str 写入字符 |
public static void main(String[] args) {
try (Writer writer = new FileWriter("./testDir/test2.txt", true)) {
writer.write('0');
char[] c = {'\n', '数', '组'};
writer.write(c);
String str = "\n字符串";
writer.write(str);
} catch (IOException e) {
e.printStackTrace();
}
}
🙉本篇文章到此结束
原文地址:https://blog.csdn.net/m0_74270127/article/details/144311249
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!