文章目录
文件操作
1. 硬盘(外存)与内存
- 我们常说的外存包括软盘、硬盘和光盘,存放在其中的数据靠磁来维持,因此可永久保存数据。
- 内存是指主板上的存储部件,CPU直接与之沟通,并用其存储数据的部件,存放当前正在使用的(即执行中的)数据和程序,它的物理实质就是一组或多组具备数据输入输出和数据存储功能的集成电路,内存只用于暂时存放程序和数据,一旦关闭电源或发生断电,其中的程序和数据就会丢失。
- 二者相比:
- 速度:内存比硬盘快很多
- 空间:内存空间比硬盘小
- 成本:内存比硬盘贵
- 持久化:内存是暂时性保存数据断电后就会丢失,硬盘可以永久性保持。
注意: 我们接下来要讲的文件操作,是对硬盘进行操作,Mysql中的操作也是主要操作硬盘。
2. 认识文件
- 狭义上的文件(file),针对硬盘这种持久化存储的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般。
- 文件内容除了数据内容以外还有文件名、文件大小、文件类型等等,我们将这部分信息视为文件的元信息(不是内容的信息)。
2.1 文件管理
对于文件的管理,我们可以通过自己的电脑发现,我们文件是按层级结构进行存储的,类似于数据结构中的树形结构。这样,一种专门用来存放管理信息的特殊文件诞生了,也就是我们平时的文件夹(folder),专业术语称为目录(directory)的概念。
所以我们如何找到我们的文件?
对于文件的查找方式我们有绝对路径和相对路径。
- 绝对路径:我们在计算机中从盘符开始一步步的向下查找,得到的路径就是绝对路径。
如:D:\qq\Bin\TXSSO
- 相对路径:从给定的某个目录,一层一层的往下找,这个过程得到的路径就是相对路径。
如:./src/刷题/day8.java
其中 .在相对路径中,表示当前目录。…表示当前目录的上级目录。
一般来说: 文件系统中的任何一个文件,对应的路径是唯一的,但是在Linux上可能存在一个文件有两个不同的路径能找到它,在Windows上不存在。
2.2 文件类型
在普通文件中,根据存储的内容不同,我们分为文本文件和二进制文件。
- 文本文件存储的数据就是遵守ASCII字符集编码或者其他字符集编码的文件,如.java、.c都是文本文件。
- 二进制文件存储的是二进制数据,不受字符集限制,如.class、.exe、.jpg、.mp3都是二进制文件。
3. Java中操作文件
3.1 文件系统的操作
Java中提供一个File类对文件(包括目录)进行抽象描述,在内存中创建一个对应的对象,通过操作对象来间接操作硬盘中的文件。
使用过程:
第一种对文件进行操作:
- 构造File对象,通过绝对路径或者相对路径都行,此时指向的文件可以真实存在也可以不存在。
- 使用File类中的方法:如下
File file = new File("./1.txt");
System.out.println(file.getParent());
//得到绝对路径
System.out.println(file.getAbsolutePath());
System.out.println(file.getName());
System.out.println(file.getPath());
//文件创建
File file2 = new File("./hello_world.txt");
System.out.println(file2.exists());
System.out.println(file2.isDirectory());
System.out.println(file2.isFile());
file2.createNewFile();//不存时在项目下创建
System.out.println(file2.isFile());
System.out.println(file2.exists());
System.out.println(file2.isDirectory());
//删除文件
file2.delete();
第二种对目录进行操作:
使用如下:
//创建目录
File file5 = new File("test-dir");
file5.mkdir();//创建一级目录
//创建多级目录
File file3 = new File("test-dir/aaa/bbb");
file.mkdirs();
//再创建一个对象,获取多级目录的内容
File file4 = new File("test-dir");
String[] results = file4.list();//返回String数组
System.out.println(Arrays.toString(results));//打印数组
File[] results2 = file4.listFiles();//返回File数组
System.out.println(Arrays.toString(results2));
//重命名,新建一个file对象,将旧的重命名给新的,就能重命名。
File dest = new File("./test-dir2");
file4.renameTo(dest);
3.2 文件内容的操作
本文上面对于文件介绍中提到根据文件内容不同分为文本文件和二进制文件,所以我们在对内容进行操作时也提供了两组类。对文本文件我们使用字符流,对应Reader、Writer。对二进制文件 我们使用字节流,对应InputStream、OutPutStream。
3.2.1 InputStream与OutPutStream的用法
二者都是抽象类,我们通过new对应的子类来对文件内容进行操作。
InputStream的用法:
- 通过InputStream类的read()方法,对文件内容进行读取
- 注意,我们使用读取完毕后一定要使用close()方法关闭文件,释放资源。
- 为了避免我们执行代码时,跳过close方法,第一种代码写法通过finally来保证close()一定被执行。
- 读到-1时,代表读完
- 代码演示:
//第一种写法,可以避免走不到close,但是不美观
// InputStream inputStream =null;
// try {
// inputStream = new FileInputStream("d:/1.txt");
//
// }finally {
// inputStream.close();
// }
//更优雅的写法,自动进行资源释放
try (InputStream inputStream = new FileInputStream("d:/1.txt")){
//读文件
//read返回的是字节1,但是此处用int接收
// int b = inputStream.read();//无参的read,一次读一个字节
while (true){
int b = inputStream.read();
if (b==-1){
break;//结束
}
System.out.printf("%x\n",b);//16进制输出
}
}
执行结果: 内容是hello,一个字符对应一个字节,我们读出来的是字符对应的ASCII编码
内容是你好,一个汉字对应三个字节,我们输出的就是6个编码,这个一般对应的是utf-8字符集。
OutputStream的用法:
- 通过OutputStream的write方法写入内容。
- flush()方法保证我们缓冲区的数据刷新到设备中
- 代码演示:
package IO;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* @author zq
* outputStream的用法,写文件
*/
public class IODemo3 {
public static void main(String[] args) {
try (OutputStream outputStream = new FileOutputStream("d:/1.txt")){
//一个字节的写入
outputStream.write(97);
outputStream.write(98);
outputStream.write(99);
outputStream.flush();//保证缓冲区数据刷新到设备中
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行结果: 我们写入时会将原有内容删除。
注意: read和write方法还有另外两种用法。我们可以使用byte[]来写入和读取多个字节。read会尽可能将数组填满,write会把数组内容都写入文件。**write(byte[]b, int off,int len)**方法可以将 b 这个字符数组中从 off 开始的数据写入 os 中,一共写 len 个。read(byte[] b,int off, int len) 方法最多读取 len - off 字节的数据到 b 中,放在从 off 开始,返回实际读到的数量;-1 代表以及读完了
如图:
最多读取数组长度的内容到数组中,方法返回实际读取的数量。
3.2.1 Reader与Writer的用法
这两个的用法与字节流使用方法类似,接下来展示具体用法。
Reader的使用:
- read返回值还是int类型,由于我们通常用它读取文本文件,我们输出前先进行类型转换。
- 代码演示:
try(Reader reader = new FileReader("D:\\java\\bit\\java_bit\\src\\2.txt")) {
while (true){
int c = reader.read();
if (c==-1){
break;
}
char ch = (char)c;
System.out.print(ch);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Writer的使用:
- 代码演示:
writer.write(97);
writer.write(98);//这个写会把之前的内容清空写。
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}