IO流文件操作
File
File类主要是Java中对文件这块的操作(如删除、修改、查询等)而设计的相关类
File类的包名是java.io
,其实现了Serializable、Comparable两大接口以便于其对象可序列化和比较
File是文件和目录路径名的抽象表示,文件和目录是可以通过File封装成对象的,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。不论文件是否真的存在,都可以通过具体的操作来把File所指的文件给创建出来
import java.io.File;
public class Main {
public static void main(String[] args) {
// File(String pathname)
//通过将给名的路径名字符串转换为抽象路径名来创建新的File实例
File file1 = new File("E:\\Test\\1.txt");
System.out.println(file1);
// File(String parent, String child)
// 前者为父路径名,后者为子路径名,二者进行拼接即可得到一个完整的路径名字符串,同样转换为抽象路径名来创建File实例
File file2 = new File("E:\\Test", "aaa\\2.txt");
System.out.println(file2);
// File(File parent, String child)
// 前者为父路径对象,后者为子路径名,同样可以对二者进行拼接得到一个完整的路径名字符串,并转换为抽象路径名来撞见File实例
File fileParent = new File("E:\\Test\\bbb");
File file3 = new File(fileParent, "3.txt");
System.out.println(file3);
}
}
文件的创建
主要有三个方法
public boolean createNewFile()
:创建一个文件public boolean mkdir()
:创建一个文件夹public boolean mkdirs()
:创建带有嵌套关系的文件夹
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
File file1 = new File("E:\\IDEA\\wordSpace\\test\\test\\src\\1.txt");
file1.createNewFile(); // 用于创建一个带有后缀的文件
File file2 = new File("E:\\IDEA\\wordSpace\\test\\test\\src\\aaa");
file2.mkdir(); // 用于创建单个文件夹
File file3 = new File("E:\\IDEA\\wordSpace\\test\\test\\src\\bbb\\ccc");
file3.mkdirs(); // 用于创建有嵌套关系的文件夹
}
}
创建效果:
File类中的判断方法
boolean isDirectory()
:判断是否为文件夹boolean isFile()
:判断是否为文件boolean exists()
:判断文件是否存在
import java.io.File;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
// 指定目录和文件名
String directory = "E:\\IDEA\\wordSpace\\test\\test\\src\\example";
String fileName = "example.txt";
try {
// 1. 创建目录(如果不存在)
File dir = new File(directory);
if (dir.isDirectory() && !dir.exists()) { // 判断路径是否为文件夹且文件夹是否存在
dir.mkdirs(); // 创建所有缺失的父目录
}
// 2. 创建文件
File file = new File(dir, fileName);
boolean isCreated = file.createNewFile();
if (file.isFile() && isCreated) { // 判断所创建的是否为文件且文件是否已经存在
System.out.println("文件创建成功");
} else {
System.out.println("文件已存在或无法创建");
}
} catch (IOException e) {
e.printStackTrace(); // 处理异常
}
}
}
创建效果:
File类的获取方法
String getAbsolutePath()
:获取绝对路径String getPath()
:获取抽象路径名转化路径名字符串String getName()
:获取文件或文件夹名称String[] list()
:获取目录下所有内容,返回字符串数组File[] listFiles()
:获取目录下所有内容,返回File对象数组
创建内容如图:
import java.io.File;
public class Main {
public static void main(String[] args) {
File file1 = new File("E:\\IDEA\\WordSpace\\test\\test\\src\\example\\example1.txt");
System.out.println(file1.getAbsoluteFile()); // 获取文件/文件夹绝对路径
System.out.println(file1.getPath()); // 获取文件/文件夹的抽象路径并转化为字符串,和获取绝对路径类似
System.out.println(file1.getName()); // 获取文件或文件夹名称
System.out.println("-------------------------");
File file2 = new File("E:\\IDEA\\WordSpace\\test\\test\\src\\example");
String[] files1 = file2.list(); // 获取目录下的所有内容,返回字符串数组
for (String file : files1) { // 遍历字符串数组
System.out.println(file);
}
System.out.println("-------------------------");
File[] files2 = file2.listFiles(); // 获取目录下所有内容,返回File对象数组
for (File file : files2) { // 遍历File对象数组
System.out.println(file.getName());
}
}
}
效果如下:
FIle删除操作
boolean delete()
若删除路径是一个目录,则不能直接删除,需要先删除该目录中所有内容后才能删除目录
若删除路径是一个文件,则可以直接删除
// 使用循环删除
import java.io.File;
public class Main {
public static void main(String[] args) {
File dir = new File("E:\\IDEA\\WordSpace\\test\\test\\src\\example");
String[] files = dir.list(); // 获取路径文件夹中的所有文件名
for (int i = 0; i < files.length; i++) {
File file = new File(dir, files[i]); // 获取文件夹下的文件路径
file.delete(); // 删除文件
}
dir.delete();
}
}
// -------------------------------------------------------------------
// 使用递归删除
import java.io.File;
public class Main {
public static void main(String[] args) {
File dir = new File("E:\\IDEA\\WordSpace\\test\\test\\src\\aaa");
deleteAllFiles(dir);
}
public static void deleteAllFiles(File file) {
File[] files = file.listFiles(); //获取文件夹路径下的所有文件
if (files == null) { // 若路径下没有文件,则直接返回不用进行删除操作
System.out.println("该路径下已无文件");
return;
}
for (File f : files) { // 遍历目录中的所有内容
if (f.isDirectory()) { // 若是文件夹,则递归调用本方法来进一步删除文件夹下的内容
deleteAllFiles(f);
} else { // 为文件,则直接删除
System.out.println("已删除文件:" + f.getPath());
f.delete();
}
}
file.delete(); // 最后删除文件夹
}
}
IO流
IO:输入(Input)/输出(Output),即输入数据以及写数据
流:是一种抽象概念,是对数据传输的总称,即数据在设备间的传输称为流,流的本质是数据传输
IO流就是用来处理设备间数据传输问题的
IO流常见的应用即文件上传、下载、复制等
IO流的分类:
- 根据数据流向来分:
输入流:读数据,将硬盘中的数据读取到内存中
输出流:写数据,将程序中的数据写入到硬盘中 - 根据数据类型来分:
字节流:字节输入流/字节输出流
字符流:字符输入流/字符输出流 - IO应用场景:
纯文本文件,优先使用字符流
图片、视频、音频等二进制文件,优先使用字节流
不确定文件类型,优先使用字节流,可以说字节流是万能流
字节流
字节流输出数据
InputStream
:这个抽象类是表示字节输入流的所有类的超类OutputStream
:这个抽象类是表示字节输出流的所有类的超类
特点:子类名称都是以其父类名作为子类名的后缀FileOutputStream
:文件输出流用于将数据写入FileFileOutputStream(Stringname)
:创建文件输出流以指定的名称写入文件
输出流步骤:
1、调用系统功能创建了文件
2、创建字节输出流对象
3、字节输出流对象指向文件
字节流写入数据常用的三种方式:
void write(int b)
:将指定的字节写入此文件输出流,一次写一个字节数据void write(byte[] b)
:将b.length
字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据void write(byte[] b, int off, int len)
:将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流,一次写一个字节数组部分的数据
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream1 = new FileOutputStream("src\\1.txt");
fileOutputStream1.write(97); // 一个一个的写入
fileOutputStream1.write(98); // 这里的数据不一定是数字类型,直接使用字符也是可以的
fileOutputStream1.write(99);
FileOutputStream fileOutputStream2 = new FileOutputStream("src\\2.txt");
byte[] bytes = {97,98,99,100};
fileOutputStream2.write(bytes); // 将bytes中的所有数据直接写入
fileOutputStream2.write("this is a test".getBytes()); // 通过getBytes()方法写入
FileOutputStream fileOutputStream3 = new FileOutputStream("src\\3.txt");
fileOutputStream3.write(bytes, 1, bytes.length - 1); // 从bytes的第一个元素开始写入到最后一个元素
fileOutputStream1.close();
fileOutputStream2.close();
fileOutputStream3.close();
}
}
字节流数据若要换行则可以使用转义字符\r
或\n
都可以
字节流数据若要追加写,则可以通过使用FIleOutPutStream(File, true))
其中表示第二个参数若为true,则字节流写入文件的末尾
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream f = new FileOutputStream("src\\1.txt", true); // 设置第二个参数为true,表示可以进行持续写入
f.write(("This is test1").getBytes());
f.write('\n');
f.write(("This is test2").getBytes());
f.close();
}
}
上面的代码中都发现了一个函数,即close()
,该函数可以释放文件资源,但需要规范使用:
- 当文件为null时是不能释放资源的
- 当文件已经打开使用,程序遇到报错而中断时,同样需要进行资源的释放
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream f = null;
try {
f = new FileOutputStream("src\\test.txt");
f.write(("This is a test").getBytes());
} catch (Exception e) {
e.printStackTrace();
} finally { // 使用finally关键字,即使程序在运行过程中出现报错而中断都会继续运行
if (f == null) {
try {
f.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
字节流读取数据
上面介绍了如何将内容写入磁盘中,而将磁盘文件中的数据读取出来的话,可以使用到
FileInputStream
:从文件系统中的文件获取输入字节FileInputStream(Stringname)
:通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名
读取数据步骤:
1、创建字节输入流对象
2、调用字节输入流对象的读数据方法
3、释放资源
字节流读取磁盘文件数据的常见方法:
int read()
:从该输入流读取一个字节数据,返回值为-1时说明文件读取完毕
import java.io.FileInputStream;
public class Main {
public static void main(String[] args) {
FileInputStream f = null;
try {
f = new FileInputStream("src\\test.txt");
int read = f.read();
while (read != -1) { // 循环读取,当f.read == -1时表示文件已全部读取完毕
System.out.print((char) read); // 将读取的int类型数据转换为char类型
read = f.read(); // 持续循环读取下一个数据
}
/*
* int read;
* while ((read = f.read()) != -1) {
* System.out.print((char) read);
* }
* 或者这样同样也可以对磁盘文件数据进行循环读取
* */
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
f.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
了解了数据的读取后,就很轻松的能够实现将一个文件的数据复制到另一个文件中了
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class Main {
public static void main(String[] args) {
FileInputStream input = null;
FileInputStream output = null;
try {
input = new FileInputStream("src\\test.txt");
output = new FileInputStream("src\\1.txt");
int read;
while ((read = input.read()) != -1) {
FileOutputStream clone = new FileOutputStream("src\\1.txt", true);
clone.write(read);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
input.close();
output.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
上述字节流数据读取都使用到了循环读取,使用循环读取单次只能读取一个数据,就好比你需要喝水,此时饮水机在滴水,然后你对着龙头一滴一滴的喝,这样效率是很差的
我们一般都是使用一个容器,先把装水装进来,然后再一次性喝下去,这样的效率就会高很多。于是对于字节流数据的读取就可以使用字节流读取字节数组数据
// 文本的复制
import java.io.FileInputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream f = new FileInputStream("src\\test.txt");
byte[] buf = new byte[1024]; // 将数据全部存入字节数组中
int len = f.read(buf); // 利用字节流读取字节数组数据
System.out.println(new String(buf, 0, len));
f.close();
}
}
// ---------------------------------------------------
// 图片的复制
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream input = new FileInputStream("src\\test.jpg");
byte[] buf = new byte[1024];
int len;
FileOutputStream output = new FileOutputStream("src\\1.jpg");
while ((len = input.read(buf)) != -1) {
output.write(buf, 0, len);
}
input.close();
output.close();
}
}
对于字节数组的大小,通常定义为1024的整数倍,因为1024正好代表1kb的数据
字节缓冲流
用专业术语来说的话:
传统方式一个字节一个字节读取或者写入数据,会频繁的发生系统内核的调用(用户态与内核态之间的切换),效率十分的低下
于是我们可以使用到字节缓冲流,缓冲区是一个内存区域的概念,以块为单位写入或读取数据,用来减少系统的调用频率
BufferedInputStream(InputStream in)
:字节缓冲输入流BufferedOutputStream(OutputStream out)
:字节缓冲输出流
和一般字节流不同的是,字节缓冲流对象的构造函数传递字节流对象,并不是文件路径,缓冲流提供了一个缓冲去,做好了封装,以块的形式读写数据,但腹泻数据依然依赖于字节流对象
注意:字节缓冲流的缓冲区大小默认为8kb,即8192字节
对于字节缓冲流的使用,其实是比较简单的
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
// 创建字节输入缓冲流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("src\\test.jpg"));
// 创建字节输出缓冲流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("src\\1.jpg"));
int len;
byte[] buf = new byte[1024]; // 创建缓冲块
while ((len = bis.read(buf)) != -1) { // 持续按缓冲块读取文件数据
bos.write(buf, 0, len); // 持续按缓冲块写文件数据
}
bis.close();
bos.close();
}
}
字符流
字符流,实际上是对字节流的包装,像是读取文件、文本类型优先使用字符流,它可以对文件去做一些编码和解码
- Writer是写入字符流的抽象类
OutputStreamWriter
(输出转换流):为字符流通向字节流的桥梁,将要写入流的字符编码成字节
构造方法1:OutputStreamWriter(OutputStream out)
:用于创建使用默认字符编码的OutputStreamWriter
构造方法2:OutputStreamWriter(OutputStream out, String charseName)
:用于创建使用默认字符编码的OutputStreamWriter
字符流的底层还是用字节流进行读写,字符流仅仅是做了字节和字符的转换,即编码与解码
接收字符数据,首先要把字符数据变成字节数据,然后再用普通字节流,把数据写到硬盘,以此实现字符数据转换为字节数据
- Reader是用于读取字符流的抽象类
InputStreamReader
(输入转换流):为字节流通向字符流的桥梁,将读取字节并将其解码成字符
构造方法1:InputStreamReader(InputStream in)
:用于创建一个使用默认字符集的InputStreamReader
构造方法2:InputStreamReader(InputStream in, String charserName)
:用于创建使用指定字符集的InputStreamReader
接收字节流,转换成字符流,底层会用字节流去硬盘读取字节数据,把字节数据转换为字符数据,然后返回,以此实现字节数据转换为字符数据
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
// 字符输入流
InputStreamReader isr = new InputStreamReader(new FileInputStream("src\\test.txt"));
// 字符输出流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("src\\1.txt"));
char[] buf = new char[1024]; // 创建缓冲区
int len;
while ((len = isr.read(buf)) != -1) {
osw.write(buf, 0, len); // 将读取到的文本内容写入到1.txt下
}
isr.close();
osw.close();
}
}
转换流的便捷形式FileWriter
与FileReader
:使用更为便捷
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
// 字符输入流
FileReader fr = new FileReader("src\\test.txt");
// 字符输出流
FileWriter fw = new FileWriter("src\\1.txt");
char[] buf = new char[1024]; // 创建缓冲区
int len;
while ((len = fr.read(buf)) != -1) {
fw.write(buf, 0, len); // 将读取到的文本内容写入到1.txt下
}
fr.close();
fw.close();
}
}
字符缓冲流
与字节缓冲流一样的道理,字符同样也有缓冲流
BufferedReader
:从字符输入流读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取BufferedWriter
:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入FileReader
、FileWriter
:内部使用InputStreamReader、InputStreamWriter,解码过程由字节变为字符,默认的缓存大小为8kbBufferReader
、BufferWriter
:字符缓冲写入流、字符缓冲输入流。默认缓存大小为8kb,可以手动指定缓存大小,把数据读取到缓存中,减少每次转换过程,使效率更高
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("src\\test.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("src\\test2.txt"));
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
}
br.close();
bw.close();
}
}
上面这种就是读取文本文件中数据最简单的形式了
至此IO流文件操作的学习到此结束