一、Java I/O流整体框架说明介绍
注意:作为程序员是站在内存的角度看待输入和输出(即从文件读取数据到内存为输入,从内存将数据写入文件等持久化操作为输出,下面所述的输入流输出流均为此理解)
// I/O流分类
一、按照流向分
输入流:只能从中读取数据,而不能向其写入数据
输出流:只能向其写入数据,而不能从中读取数据
二、按照操作单元分
字节流:按照单个字节进行读取或者写入,适用于音频、视频、非文本文件等
字符流:按照单个字符进行读取或者写入,适用于文本文件
三、按照角色分
节点流(文件流):直接从/向一个特定的I/O设备(磁盘、网络)读/写数据的流
处理流(缓冲流):连接到已经存在的流(节点流或者处理流)之上通过对数据的处理为程序员提供更为强大的读写功能的流
> 转换流:属于处理流的一种,主要用于将字节输入流转换为字符输入流读取以及将字符输出流转换为字节输出流
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问字符串 | StringReader | StringWriter | ||
缓冲流(处理) | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
操作对象 | ObjectInputStream | ObjectOutputStream |
二、File类的使用
2.1 File类的基本介绍
/*
File类的使用
1. File类的一个对象,代表一个文件或者一个目录(文件夹)
2. File类声明在java.io包下
3. File类中涉及到关于文件或者文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或者读取文件内容的操作。如果需要读取或写入文件内容,必须使用IO流来完成。
4. 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"
*/
/*
File类的常用三个构造器(第四个构造器待使用)
构造器1:File(String pathname):通过将给定的路径名字符串转换为抽象路径名来创建一个新的File实例
构造器2:File(String parent, String child):用父路径名字符串和子路径名字符串创建一个新的File实例。
构造器3:File(File parent, String child):从父抽象路径名和子路径名字符串创建一个新的File实例。
构造器4:File(URI uri):通过将给定的File: URI转换为抽象路径名来创建一个新的File实例。(待完善)
*/
// 1. 构造器1示例:
File f1 = new File("F:\\English\\word.txt");
// 2. 构造器2示例
File f2 = new File("F:\\English","word.txt");
// 3. 构造器3示例
File fParentPath = new File("F:\\English")
File f3 = new File(fParentPath, "word.txt")
2.2 File对象常用方法
File f1 = new File("hello.txt");
File f2 = new File("F:\\English\\hi.txt");
// getAbsolutePath():获取文件对象文件的绝对路径
System.out.println(f1.getAbsolutePath());
// getPath():获取当前对象的pathname属性
System.out.println(f1.getPath());
// getName():获取文件名
System.out.println(f1.getName());
// getParent():获取文件的路径名,不包含文件名本身
System.out.println(f1.getParent());
// length():获取文件内容的长度
System.out.println(f1.length());
// lastModified():获取文件的最后修改时间
System.out.println(f1.lastModified());
/*
public booean renameTo(File dest);把文件重命名为指定的文件路径
例如:file1.renameTo(file2);
要想包装返回true,需要file1在硬盘中是存在的,且file2不能在硬盘中存在。
注意:这个方法类似于剪切 粘贴的效果,原来位置的文件会消失,是从一个路径将文件移动到另一个位置
*/
File file4 = new File("F:\\untitled\\jdbc.properties");
File file5 = new File("jdbc1.properties");
boolean flag = file5.renameTo(file4);
System.out.println(flag);
/*
如果文件或目录不存在则所有返回值均为默认值:false
public boolean isDirectory():判断是否是文件目录
public boolean isFile():判断是否是文件
public boolean exists():判断文件或目录是否存在(在磁盘中是否存在)
public boolean canRead():判断文件或目录是否可读
public boolean canWrite():判断文件或目录是否可写
public boolean isHidden():判断文件或目录是否隐藏
*/
/*
创建硬盘中对应的文件或文件夹
public boolean createNewFile():创建文件。若文件存在,则不创建,返回false
public boolean mkdir():创建文件目录。如果此文件目录存在,则不创建。如果此文件目录的上层目录不存在,也不创建
public boolean mkdirs():创建文件目录。如果上层文件目录不存在,一并创建
*/
// 文件目录的创建
File file2 = new File("F:\\Math\\day01");
boolean isMk = file2.mkdir();
System.out.println(isMk);
File file3 = new File("F:\\Math\\day02");
boolean isMks = file3.mkdirs();
System.out.println(isMks);
/*
删除磁盘中的文件或文件目录
public boolean delete():删除文件或者文件夹
删除注意事项:Java中的删除不走回收站,即为永久删除,无法找回
*/
// 文件的创建和删除
File file1 = new File("hi.txt");
if (!file1.exists()) {
file1.createNewFile();
System.out.println("创建成功!");
} else {
file1.delete();
System.out.println("删除成功!");
}
三、节点流的使用案例以及说明
3.1 字符输入流和字符输出流
/*
一、字符输入流"FileReader"的使用
*/
@Test
public void FileReaderTest(){
// 初始化FileReader流对象
FileReader fr = null;
try {
// 使用File类创建源文件对象
File inFile = new File("DataBaseDesc.txt");
// 将文件对象和字符输入流进行连接绑定
fr = new FileReader(inFile);
// 局部变量,用于接收read的返回值,返回值为单次读取的字符个数,如果read的返回值为-1,则代表文件读取到了末尾
int flag;
// 写法一:单个字符读取
// while ((flag = fr.read()) != -1) {
// 由于read返回值为int类型,因此输出的时候需要使用char进行强转
// System.out.print((char)flag);
// }
// 写法二:创建字符数组,单次多字符读取
char[] chs = new char[5];
while((flag = fr.read(chs)) != -1){
// 使用字符数组读取,有两种输出到控制台的正确写法
// 方法一
String s = new String(chs, 0, flag);
System.out.print(s);
// 方法二
for(int i = 0; i < flag; i++){
System.out.print(chs[i]);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fr != null){
try {
// 关闭流资源
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
二、字符输出流"FileWriter"的使用
说明:字符输出流的使用需要结合字符输出的读取后输出(即写入)到指定文件中,即在上面字符输入流的基础上进行修改得到,如下:
*/
@Test
public void fileReaderTest() {
FileReader fr = null;
// 第一处增加代码,初始化FileWriter流对象
FileWriter fw = null;
try {
File inFile = new File("DataBaseDesc.txt");
// 第二处增加代码,创建File输出的目标文件(可以不存在此文件,会自动创建)
File outFile = new File("DataBaseDesc_1.txt");
fr = new FileReader(inFile);
// 第三处增加代码,初始化FileWriter对象连接和绑定输出目标文件对象
fw = new FileWriter(outFile);
int flag;
while ((flag = fr.read()) != -1) {
// 使用单个字符读取的写入方式
fw.write(flag);
}
char[] chs = new char[5];
while ((flag = fr.read(chs)) != -1) {
// 第四处增加代码,使用字符输出流对象调用write方法将内容写入到文件中(这里使用的是字符数组,单词读取多个字符的方法读取,每次读取的内容存放在该数组中)
// 因此write方法第一个参数为该数组,0表示从字符数组的第一个元素开始写入,flag代表写入多少个字符(即单次读取了多少个字符就写入多少个字符)。
fw.write(chs, 0, flag);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 第六处增加代码,关闭字符输出流资源
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
3.2 字节输入流和字节输出流 (FileInputStream and FileOutputStream)
// 复制图片的操作(结合使用字节输入流和字节输出流)
@Test
public void testImageCopy(){
// 创建字节输入流和字节输出流对象,初始赋值为null
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
// 1. 提供输入和输出的图片文件对象
File inputFile = new File("orange.jpg");
File outputFile = new File("orange02.jpg");
// 2. 提供字节输入和字节输出的流对象
fileInputStream = new FileInputStream(inputFile);
fileOutputStream = new FileOutputStream(outputFile);
// 3. 读取和写入的操作(和字符输入输出流一样的套路)
// 3.1 创建字节数组,大写为1024
byte[] bytes = new byte[1024];
// 3.2 创建int变量,用于接收read返回值
int len;
while ((len = fileInputStream.read(bytes)) != -1) {
// 将字节数组的内容按照每次读取的字节数从第一个字节开始写入到输出文件中
fileOutputStream.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
// 关闭资源操作
if (fileInputStream != null)
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (fileOutputStream != null)
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}