文章目录
1.什么叫文件IO
1.1IO的概念
I0——input与output合称,输入与输出,那么什么叫输入什么就输出呢?我们可以根据CPU为基准,从CPU往外叫输出,从外往CPU的叫输入。如图:
1.2文件的概念
文件本身就是个广义的概念通常将软件资源与硬件资源都抽象成文件,但是在这里我们只聊狭义的文件,也就是保存在硬盘的文件。
那么文件夹算文件吗?算的,文件夹算目录文件,在我们计算机中有许多文件和目录,而且这些目录还有些嵌套的,为了将这些目录和文件给整理在一起,则计算机有个体系来整理这些文件与目录,可以看成一个N叉树。那我们怎么找到我需要的文件呢,那需要一个机制,可以帮我们迅速定位到目标文件,那么需要定位到目标文件,你肯定需要一个路径来实现吧。
路径又是什么呢?从开始位置到目标文件经过的地方,这些就叫路径,路径又分相对路径和绝对路径。
绝对路径:开始位置必须是整个文件系统的初始位置。D:\bite study code\java-ee 这个就可以称为绝对路径
当前目录:D:\bite study code\java-ee
相对路径:
当前目录:. 指的是当前java-ee文件
上一级目录:…指的是D:/bite study code
上一级目录的文件…//java 指的是bite study code 中的java文件
上述都是windows系统绝对路径和相对路径的表示方式,linux表示的方式不一样:
绝对路径:/bite study code/java-ee
相对路径与windows相同
在windows中有两种分隔符一种是/ 一种是\都可以用但也只限于windos系统中,其余都是用/分隔符表示。
2.用java来操作文件
2.1文件的分类
文件分为文本文件和二进制文件
文本文件是给程序猿看的,而二进制文件是给计算机看的
二进制文件:存储的都是二进制数据,像.docx,.pptx,.mp3,.mp4,.png等等都是二进制文件
文本文件:存储的是文本数据,像.java,.c,.html,.md等等都是文本文件
什么叫二进制数据,什么叫文本数据?
二进制数据:以字节的形式存储数据,并且是不可读的,通常是通过一些特定的软件或程序来解读的。
文本数据:以字符的形式存储数据,是可读的,是通过字符编码规则表示的像UTF8和GBK这些字符编码规则。
2.2如何区分二进制文件和文本文件
一个比较暴力的方式:直接将要区分的文件放入记事本中,如果显示的是字符那么就是文本文件,如果是一些乱码那么就是二进制文件。
2.3java操作文件系统
java在对操作文件系统提供了一个类——File类,其中的方法可以实现以下的需求:
- 创建文件
//根据File对象自动创建一个空文件,创建成功之后就返回true,只有第一次创建只会会返回true
// 后续执行这个语句只会返回false,说明不能创建相同路径的文件
System.out.println(file.createNewFile());
//根据File对象创建文件夹
//System.out.println(file.mkdirs());
- 删除文件
//根据File对象,删除该文件,成功删除返回tru
//file.delete();
- 创建目录
//根据File对象创建文件夹
//System.out.println(file.mkdirs());
//判断File对象代表的文件是否是一个目录
//System.out.println(file.isDirectory());
- 重命名文件
//重命名
file.renameTo(file);
2.4java操作文件内容
java提供了“流”一组类,来操作文件内容,主要核心就两类,一类为字节流,一类为字符流
字节流对应的就是二进制文件 InputStream/OutputStream 以字节为单位写数据读数据
字符流对应的就是文本文件 Reader/Writer 以字符为单位写数据读数据
这两个类的核心操作就是,根据构造方法打开文件,然后通过read读文件write写文件,通过close关闭文件
2.4.1读文件
字节流:
InputStream类是一个抽象类,不能被实例化,所以java标准库就提供了一个子类FileInputStream
这里的输入流是指将数据从文件中读入程序中,输入流不仅仅只是文件,还可以是键盘输入、网络连接、传感器。
InputStream inputStream = new FileInputStream("./text.txt");
//FileInputStream括号中填写已经创建好File对象或者直接填写路径,但是这个文件必须是存在的,不然就会抛异常
输入类提供了read方法,但这个方法有几个版本:
版本1:read()无参数版本,返回类型是int,每一次从文件中读取一个字节的数据,直到将文件中的数据读完就返回-1。
注意:此处返回int为什么不是byte?
- 为了当将文件数据读完之后返回-1的时候好表示
- 因为byte类型是有符号的,所以为了读取的数据全为正数,则用无符号类型int作为返回类型
- 此处为什么不用short,short不比int又少两个字节,节约空间不好吗,放在以前这种想法是可以的,但现在的cpu最低都是32位的,也就是说最低就是一个int,用short的话,CPU还要将short转化位int去运行,这样加大了CPU的任务,降低了CPU的工作效率。
public static void main(String[] args) throws IOException {
File file = new File("./text1.txt");
file.createNewFile();
InputStream inputStream = new FileInputStream(file);
while(true) {
int a = inputStream.read();
if(a == -1) {
//读取完毕
break;
}
System.out.printf("0x%X ",a);
}
}
版本2:read( b)带一个参数的,参数的类型是byte[],我们要先创建一个空的byte[],然后通过read方法将文件中
的数据读入到byte[]数组中,这种写法是经典的"输出型参数" 用参数作为函数的返回结果。在C++很常见,但在java比较少见。
byte[] bytes = new byte[1024];
int b = inputStream.read(bytes);
System.out.println("b = " + b);
for (int i = 0; i < b; i++) {
System.out.printf("0x%X",bytes[i]);
}
b这个变量指的是读取到了多少个字节
此处的printf打印适用于格式化输出,可以格式化字符串和变量:
- %d 十进制整数
- %f 浮点数
- %s 字符串
- %x 十六进制数
println适用于直接打印字符串、数字、对象。
版本3:read(byte[] b,int off,int len) 只填充部分数组的一部分,从off下标开始,填充len长度。在网络通信中很常见
byte[] bytes = new byte[1024];
int c = inputStream1.read(bytes,0,10);
for (int i = 0; i < c; i++) {
System.out.printf("ox%x ",bytes[i]);
}
字符流:
Reader类是一个抽象类,不能被实例化,java也提供了一个子类FileReader
这个字符输入流提供了read()方法,也提供了几个版本,这里我描述一些三个版本
版本1:无参数一个一个的从文件中读到程序中
/*try(Reader reader = new FileReader("./text.txt")) {
while(true) {
int a = reader.read();
if(a == -1) {
break;
}
char ch = (char) a;
System.out.println(ch);
}
}*/
版本2:版本2:带一个参数的,参数类型为char[]
/*try(Reader reader = new FileReader("./text.txt")) {
char[] ch = new char[1024];
int a = reader.read(ch);
for (int i = 0; i < a; i++) {
System.out.println(ch[i]);
}
}*/
版本3:带三个参数 分别为参数类型char[],int off,int len
try(Reader reader = new FileReader("./text.txt")) {
char[] ch = new char[1024];
int a = reader.read(ch,0,2);
for (int i = 0; i < a; i++) {
System.out.println(ch[i]);
}
}
2.4.2写文件
字节流:
OutputStream也是一个抽象类,不能被实例化,java也提供了一个子类FileOutputStream
这个输出流是指将数据在程序中写入文件中,提供了write方法来将程序中的数据写入文件中,也提供了3个版本的write()
版本1:write()无参的,一个一个将程序中的数据读入文件中
/*outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.write(100);*/
版本2:write() 只有一个参数byte[]类型的,先将byte数组初始化,然后将byte数组中的内容读入文件中
/*byte[] bytes = new byte[1024];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = 1;
}
outputStream.write(bytes);*/
版本3:write()三个参数,byte[] b ,int off,int len 分别为byte类型的数组,开始读入的下标和需要读入文件的长度。
/*byte[] bytes = new byte[1024];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = 1;
}
outputStream.write(bytes,0,10);*/
上述的write操作,都会覆盖之前的数据,为了不覆盖之前的数据,这个覆盖操作不是write造成的,而是打开文件这个操作造成的,在打开文件的构造方法中,加一个参数true,那么就不会覆盖之前的数据。
try(OutputStream outputStream = new FileOutputStream(file,true)) {
byte[] bytes = new byte[1024];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = 1;
}
outputStream.write(bytes,10,20);
}
字符流:
Writer是一个抽象类,不能被实例化,java也提供了一个子类FileWriter
提供了一个write方法
版本1:无参数,一个一个从程序写入文件中
try(Writer writer = new FileWriter("./text.txt",true)) {
writer.write(',');
writer.write('我');
writer.write('来');
writer.write('了');
}
版本2:有一个参数,char[]类型,一个数组大小的写入文件
char[] ch = new char[1024];
for (int i = 0; i < ch.length; i++) {
ch[i] = '好';
}
try(Writer writer = new FileWriter("./text.txt",true)) {
writer.write(ch);
}
版本3:传String类型的数组
String str = "hhhhhhhhhhhhhhh";
try(Writer writer = new FileWriter("./text.txt")) {
writer.write(str);
}
2.4.3关闭文件——close()
打开文件的时候,就会在操作系统内核pcb结构体中"文件描述符表"添加一个元素,这个元素表示当前打开文件的相关信息。,这个文件描述符表类似于数据结构中的顺序表,它不会自动扩容,所以当这个顺序表达到了上限,那么就无法其他文件,所以我们需要在结束对这个文件操作之后就关闭这个文件也就是删除顺序表对应的元素。
java中提供了一个接口,调用这个接口,运用try关键字就可以在程序运行完之后自动去调用close方法,这个接口就是Closeable。
try(InputStream inputStream1 = new FileInputStream("./1.png")){
byte[] bytes = new byte[1024];
int c = inputStream1.read(bytes,0,10);
for (int i = 0; i < c; i++) {
System.out.printf("ox%x ",bytes[i]);
}
}