File类是什么?
1.在读写数据时告诉JVM要操作的文件或文件夹在哪。
2.对文件或文件夹本身进行操作。包括创建,修改,删除等操作。
IO流是什么?
1.可以将数据从本地文件中读取出来。
2.可以将数据从内存中保存到本地文件。
File类的构造方法
1.File时文件和目录路径名的抽象表示。
2.文件和目录可以被File封装成对象。
3.File封装的对象仅仅是一个路径名,它可以存在也可以不存在。
4.构造方法:
- File(String pathname) // 通过给定路径名字符串转换为抽象路径名来创建File实例。
- File(String parent, String child) // 从父路径名字符串和子路径名字符串创建File实例。
- File(File parent, String child) // 从父抽象路径名和子路径名字符串创建File实例。
解释:为了使用File中的方法。所以要把路径封装成字符串给File。
//三种构造方法创建a.txt文件
File f1 = new File("D:\\DeskTop\\a.txt");
String path1 = "D:\\DeskTop";
String path2 = "a.txt";
File f2 = new File(path1, path2);
File ff = new File("D:\\DeskTop");
File f3 = new File(ff, path2);
绝对路径和相对路径
1.绝对路径:从盘符开始的路径的完整串。
2.相对路径:相对当前项目而言的路径。
File的创建功能
1.public boolean createNewFile() // 创建一个新的空的文件。
2.public boolean mkdir() // 创建一个文件夹,不管调用者有没有后缀,它只能创建文件夹。
3.public boolean mkdirs() // 创建一个多级文件夹,也可以创建单级文件夹,不管调用者有没有后缀,它只能创建文件夹。
File类的删除方法
1.public boolean delete() // 删除文件,或文件夹。
注意:
- 该方法删除是直接从硬盘删除,不进回收站。
- 删除文件夹时只能删除空的文件夹,不能删除有内容的文件夹。
- 若想删除有内容的文件夹,只能先进入这个文件夹将里面内容删空后再删该文件夹。
File类的获取和判断功能
1.public boolean isDirectory() // 判断此抽象路径名表示的File是否为目录。
2.public boolean isFile() // 判断此抽象路径名表示的File是否为文件。
3.public boolean exists() // 判断此抽象路径名表示的File是否存在。
4.public String getName() // 获取由此抽象路径名表示的文件或目录的名称。
File类的高级获取功能
1.public File[] listFiles() // 返回目录中所有的文件和文件夹的File数组。
注意:
- 当调用者时一个文件时:返回null。
- 当调用者是一个空文件夹时:返回File类型的空数组。
- 当调用者是一个有权限才能进入的文件夹时:返回null。
IO流
目的:
1.写数据,将数据写到文件中,实现永久化存储。
2.读数据,将文件中的数据读取至内存。
3.I 也就是input,O也就是output。
4.以内存为参照物进行读写。
IO流的分类
什么是纯文本文件:
1.Windows记事本能打开的文件,并且内容没有出现乱码的文件。
字节流
输入输出是以内存为参照,从内存写到硬盘,数据从内存流出了所以是输出。输入流则是从硬盘读取到内存的流。
1.写数据:
// 创建字节输出流对象
FileOutputStream fileOutputStream = new FileOutputStream("D:\\a.txt");
// 写数据
fileOutputStream.write(97); // 写入字符a
// 关闭流,释放资源
fileOutputStream.close();
结论:
- 若写的文件存在,会把文件清空并写出指定内容。
- 若文件不存在,会自动创建一个。
写数据的三种方式
注意:
1.写换行符时:windows : \r\n,Linux:\n,Mac:\r。
如何写数据时不清空原来的内容:
// 创建字节输出流对象,续写开关 true打开,false关闭
FileOutputStream fileOutputStream =
new FileOutputStream("D:\\a.txt", true);
try…catch捕获异常
FileOutputStream fileOutputStream = null;
try {
// 创建字节输出流对象,续写开关 true打开,false关闭
fileOutputStream = new FileOutputStream("D:\\a.txt", true);
// 写数据
fileOutputStream.write(97);
}catch (Exception e){
e.printStackTrace();
} finally { // 此处代码不管有没有触发异常一定会被执行
// 关闭流
if(fileOutputStream != null){ // 若创建对象之前有代码可能没有到创建字节输出流时发生异常。
try{
fileOutputStream.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
2.读数据:
字节输入流
FileInputStream file = null;
try {
// 创建字节输入流
file = new FileInputStream("D:\\a.txt");
int read = file.read();
System.out.println(read);
}catch (Exception e) {
e.printStackTrace();
} finally {
if(file != null){
try{
file.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
结论:
- read()方法读取的是字节信息,若像看字符需要强转为char类型。
- 一次只能读取一个字节,返回值是读到的当前字节码点数据。
- 读取的文件必须存在。
读取多个数据:
// 创建字节输入流
file = new FileInputStream("D:\\a.txt");
int read = 0;
while((read = file.read()) != -1) {
System.out.println((char)read);
}
file.close();
文件复制
// 文件复制
FileInputStream fread = null;
FileOutputStream fwrite = null;
try{
fread = new FileInputStream("D:\\a.txt");
fwrite = new FileOutputStream("D:\\b.txt");
int r = 0;
while((r = fread.read()) != -1){
fwrite.write(r);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(fread != null){
try {
fread.close();
}catch (IOException e){
e.printStackTrace();
}
}
if(fwrite != null){
try {
fwrite.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
定义小数组拷贝
上述文件复制的效率相当慢,第一个字节写一个字节,大大降低了效率。若能一次读完再写出,那将会大大提高效率,优化代码如下。
FileInputStream fread = null;
FileOutputStream fwrite = null;
try{
fread = new FileInputStream("D:\\桌面\\a.txt");
fwrite = new FileOutputStream("D:\\桌面\\b.txt");
byte[] r = new byte[1024]; // 一次读取多个字节放入其中
int len;
while((len = fread.read()) != -1){ // 此时read()方法返回的是读取到的有效字节的个数
fwrite.write(r, 0, len);
}
}catch (Exception e){
e.printStackTrace();
}finally {
if(fread != null){
try {
fread.close();
}catch (IOException e){
e.printStackTrace();
}
}
if(fwrite != null){
try {
fwrite.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
原理:
字符流
既然字节流可以操作所有文件,为什么还要存在字符流。
字节流在读写中文时有可能出现乱码。
原因:
1.计算机中信息的存储都是二进制表示的。
2.编码:按照某种规则,将字符变成二进制再存入计算机中,这个过程称为编码。
3.解码:以相同规则,将字符的二进制表示方式变成字符的过程称为解码。
4.编码和解码的方式应该保持一致,若不一致则会导致乱码。
所以可以总结一下乱码原因:
1.字节流一次只能读取一个字节,而中文再IDE中默认UTF-8编码的,一个汉字对应三个字节,所以每次读到的是不完整的,所以出现了乱码。
字符流
底层:字节流+编码表 来实现。
注意:只要是中文,不管在哪个码表中,第一个字节一定是负数。
1.字符输出流:
构造: FileWriter类
字符流写数据的 5 种方式:
- void write(int c) // 写一个字符
- void write(char[] cbuf) // 写一个字符数组
- void write(char[] cbuf,int off,int len) // 写一个字符数组的一部分
- void write(String s) // 写一个字符串
- void write(String s,int off,int len) // 写一个字符串的一部分
注意:
- 若创建对象文件不存在,自动创建文件并写出。
- 文件夫路径必须存在。
- 创建字符输出流对象如果文件已经存在,则会自动清空文件并写出。
2.字符输入流:
构造: FileReader类
缓冲流
字节缓冲输入流
构造方法:
1.BufferedInputStream(InputStream in) // 创建一个缓冲流放入参数供以后使用,此时缓冲流默认8192长度的byte数组。
2.BufferedInputStream(InputStream in, int size) // 创建一个有指定大小的缓冲流放入参数供以后使用。
字节缓冲输出流
构造方法:
1.BufferedOutputStream(OutputStream in) // 创建一个缓冲流放入参数供以后使用,此时缓冲流默认8192个长度的byte数组。
2.BufferedOutputStream(OutputStream in, int size) // 创建一个有指定大小的缓冲流放入参数供以后使用。
为什么入参需要的是一个字节流,而不是文件路径?
因为缓冲流仅仅提供一个缓冲区,而真正的读写数据还得是基本字节流对象对数据的具体操作。
原理:
可优化部分
字符缓冲输入流
特有方法:
1.String readLine() // 自动读取一整行内容,但是不会读到换行符。该方法只有BufferedReader中有。若读不到数据返回null而不是-1。
2.BufferedReader:可将文件中的数据高效读取。
// 创建字符输入缓冲流对象
BufferedReader file = new BufferedReader(new FileReader("D:\\a.txt"));
字符缓冲输出流
特有方法:
1.void newLine() // 自动写出换行符。该方法只有BufferedWriter中有。该方法可一自动识别操作系统换行符所系要的类型。具有跨平台性。
BufferedWriter:可将字符流中的数据高效写出。
2.BufferedWriter:可将字符流中的数据高效写出。
// 创建字符输出缓冲流对象
BufferedWriter file = new BufferedWriter(new FileWriter("D:\\a.txt"));
flush和close方法
1.flush() // 该方法 刷新流,继续使用,刷新时将数据从流刷到目标中。
2.close() // 该方法 关闭流,但在关闭之前先刷新流,关闭后该流不能再使用。
字节流和字符流的使用场景
1.文件拷贝:一律使用字节流。
2.文件读取:使用字符流的字符输入流。
3.文件写出:使用字符流的字符输出流。