第七章:IO流
一:File文件类概括
(一)File两大分类
文件类的操作包括对两大分类的操作:文档和文件夹
(二)File文档的操作(isFile)
/**
* 第一部分:文件的操作
*/
@Test
public void testA() throws IOException {
//1.1) 先实例化File对象,并且指定文件的绝对路径,即包括位置和文件名
File file = new File("D:\\有道云翻译\\aaa.txt");
//1.2) 判断文件是否存在
boolean exists = file.exists();
//1.3) 如果不存在,那么创建一个此文件
if (!exists){
boolean newFile = file.createNewFile();
}
//1.4) 判断这个文件是文件还是目录
boolean file1 = file.isFile();
System.out.println("file1 = " + file1); //true是文件
boolean directory = file.isDirectory();
System.out.println("directory = " + directory); //false 不是目录
//1.5)获取对象的文件名
String name = file.getName();
System.out.println("name = " + name); //name = aaa.txt
//1.6) 获取当前文件的绝对路径 字符串形式
String absolutePath = file.getAbsolutePath();
System.out.println("absolutePath = " + absolutePath); //absolutePath = D:\有道云翻译\aaa.txt
//1.7) 在当前文件的绝对路径下创建文件,相当于newFile
File absoluteFile = file.getAbsoluteFile();
System.out.println("absoluteFile = " + absoluteFile);
boolean b = absoluteFile.equals(file);
System.out.println("b = " + b); //返回的是true,说明指向同一文件对象
//1.8)获取当前文件所在的盘的内存空间,单位是Byte位
long totalSpace = file.getTotalSpace();
System.out.println("totalSpace = " + totalSpace/1024/1024/1024 + "GB");
//1.8) 获取当前文件所在位置的剩余空间
long freeSpace = file.getFreeSpace();
System.out.println("freeSpace = " + freeSpace/1024/1024/1024 + "GB");
//1.9) 查看文件是否可读可写
boolean b1 = file.canRead(); //是否可读
System.out.println("b1 = " + b1);
boolean b2 = file.canRead(); //是否可写
System.out.println("b2 = " + b2);
boolean b3 = file.canExecute(); //查看是否可执行此文件
//1.10 获得文件的父路径
String parent = file.getParent();
System.out.println("parent = " + parent); //parent = D:\有道云翻译
String path = file.getPath();
System.out.println("path = " + path); //path = D:\有道云翻译\aaa.txt
//1.11) 获得文件的大小
long length = file.length();
System.out.println("length = " + length);
//1.12) 删除文件
file.delete();
}
(三)对文件夹的操作(isDirectory)
/**
* 第二部分:对目录的操作
*/
@Test
public void testB() throws IOException {
//2.1) 初始化文件对象
File file = new File("D:\\aa\\bb\\cc\\dd/ee");
//2.2) 判断是否存在此文件
if (!file.exists()){
//不存在那么就创建这个文件
// boolean mkdir = file.mkdir(); //这是创建单个文件夹
boolean mkdirs = file.mkdirs(); //一次创建对个下层文件夹
System.out.println("newFile = " + mkdirs);
}
//2.3) 判断此文件是文档还是目录
boolean directory = file.isDirectory();
System.out.println("directory = " + directory);
boolean file1 = file.isFile();
System.out.println("file1 = " + file1);
//2.4) 遍历目标数组
//2.4.1) 遍历此目录下的所有目录和文件,是一级目录文件,无法拿到其子子文件夹[不常使用]
File file2 = new File("D:\\aa");
String[] list = file2.list();
for (String s : list) {
System.out.println("s = " + s); //bb,
}
//2.4.2)遍历出目录下的子目录或文件的对象数组[经常使用]
File[] files = file2.listFiles();
for (File file3 : files) {
String absolutePath = file3.getAbsolutePath();
System.out.println("absolutePath = " + absolutePath); //absolutePath = D:\aa\bb
}
//2.5) 为目录或者文件更改名称(剪切重命名)
File f = new File("D:/aa/a.txt");
f.renameTo(new File("D:\\aa\\bb\\b.txt"));
}
(四)查看一个文件夹下的所有文件(包括子文件夹下的和文档)
我们需要判断文件对象是文档还是文件夹,如果是文件夹,那么就获取其下面所有文件,如果是文档就直接获取其抽象路径名称,然后递归此方法就行了
@Test
public void testC(){
//1.1) 初始化文件对象
File file = new File("D:\\零碎学习软件");
testGet(file);
}
private void testGet(File file) {
//1.2) 获取当前文件的文件数组
File[] files = file.listFiles();
//1.3) 遍历此数组,如果是文件夹那么在此遍历文件夹底下的所有文件再判断
for (File file1 : files) {
if (file1.isDirectory()) {
//如果是,那么就拿到此文件名和继续遍历此文件夹
String aa = file1.getAbsolutePath();
System.out.println("目录: " + aa);
testGet(file1);
} else {
//如果不是文件夹就输出文件名
String absolutePath = file1.getAbsolutePath();
System.out.println("文档:" + absolutePath);
}
}
}
二:IO流的分类
(一)什么是IO
- I:Input---------》输入
- O:output------》输出
- 通过IO可以完成硬盘文件的读写操作
(二)IO流的分类
- 按照流的方向的不同可分为:输入流和输出流,我们以内存或者正在执行的程序为参照物,外界到内存为输入,内存到外界为输出
- 按照读取数据的方式不同:分为字节流和字符流,
- 字节流:InputStream 和 OutputStream,他们都是抽象类,只能通过其子类实例化!字节流是一次读取一个字节,即1个byte,8位。可以读取任何文件
- 字符流:Reader和Writer,他们都是抽象类,只能通过其子类实例化! 字符流是一次读取一个字符,即char,2字节,16位。只能读取记事本能打开的普通文本文档,其中一个中文占用2个字节
(三)IO流下常用的16个类
(壹):文件流专属
①:字节流
- FileInputStream
public class TestByteSteam {
/**
* 字节输入流:InputStream。用法
* 是从外部读取文件到内存中,
*/
@Test
public void testA() throws IOException {
//1.1)先将文件定义成对象
File file = new File("D:\\有道云翻译\\SumatraPDF-settings.txt");
//1.2) 定义字节输入流对象,并且将文件对象传进去
FileInputStream fis = new FileInputStream(file);
// //1.3 循环遍历每个字节(方法一:)
// for (int i = 0; i < file.length(); i++) {
// //1.3.1) 调用读取的方法(方法一,一次读一个字节)
// int read = fis.read(); //返回的是此字节的Ascii码
// //1.3.2)将此字节转化为字符
// char ch = (char) read;
// System.out.print(ch);
// }
//1.3) 通过储存到一个数组,再将数组转化为字符串数组即可
byte[] b = new byte[(int) file.length()]; //file.length()返回是long类型
int read = fis.read(b); //将文档放到数组中,返回的是字节的总数
//1.4) 将b数组中存储的字节转化为字符串
String s = new String(b); //字符串已经有把Byte数组转化为字符串的方法,直接传入即可
System.out.println(s);
//1.5) 关闭流
fis.close();
}
- FileOutputStream
/**
* 字节输出流:OutputStream:从内存写入文件到文件中
*
*/
@Test
public void testB() throws IOException {
//2.1) 定义一个文件对象
File file = new File("D:\\a\\a.txt");
//2.2) 判断此此文件是否存在,如果不存在1,就创建一个文件
if (!file.exists()){
//2.3) 创建文件
file.createNewFile();
}
//2.4) 定义一个字节输出流的子类对象,并指定要写入到的文件对象
FileOutputStream fos = new FileOutputStream(file);//这个构造方法是覆盖的形式
// FileOutputStream fos = new FileOutputStream(file,true); //这是在原来的基础上在后面添加新内容
//2.5) 定义一个需要写入的字符串
String str = "dsadsasda";
//2.6) 将字符串转化为byte数组中
byte[] b = str.getBytes();
//2.6) 将数组中的元素写入输出流中
fos.write(b);
//关闭流
fos.close();
}
- 读和写一起操作
/**
* 将文档内容复制到其他文档里,需要先读取到数组中,再从数组中拿出来写入到其他文档类
* 分析:我们需要拿到被复制的文件对象,再拿到复制到的文件对象,然后创建直接输入流对象,将文件读取到数组中
* 然后定义直接输出流对象,将数组中的元素写入到新文件对象内
*/
@Test
public void testC() throws IOException {
//3.1)拿到需要被复制的文件对象
File oldF = new File("D:\\有道云翻译/SumatraPDF-settings.txt");
//3.2) 拿到需要复制到的位置
File newF = new File("D:\\a/SumatraPDF-settings.txt");
//3.3) 如果文件不存在,那么就创建文件
if (!newF.exists()){
newF.createNewFile();
}
//3.4) 定义输入流对象
FileInputStream fis = new FileInputStream(oldF);
//3.5) 定义输出流对象
FileOutputStream fos = new FileOutputStream(newF);
//3.6) 定义byte数组储存读取到的文件内容
byte[] b = new byte[(int) oldF.length()];
//3.7) 将旧文件读取到数组中
fis.read(b);
//3.8) 将数组中的元素写到新文件内
fos.write(b);
//3.9) 刷新输出流
fos.flush();
//3.9) 关闭流
fis.close();
fos.close();
}
②:字符流
- FileReader
**
* 字符流:Reader 和 Writer
* 字符流特点:一次读写一个字符即2位,只能用于文本文档中
*/
public class TestCharStream {
/**
* Reader:字符读,也是抽象的类,跟直接输入流差不多用法,但是储存读取出的文件的容器为char数组
*/
@Test
public void testA() throws IOException {
//1.1)获取文件对象
File file = new File("D:\\有道云翻译/SumatraPDF-settings.txt");
//1.2) 创建字符输入流对象
FileReader fr = new FileReader(file);
//1.3) 创建储存读取数据的容器
char[] c = new char[(int) file.length()];
fr.read(c);
//1.4) 打印读取到的信息,直接打印即可,因为是字符
System.out.println(c);
//1.5) 关闭流
fr.close();
}
- FileWriter
/**
* 2.使用FileWriter写入字符文件的内容
*/
@Test
public void testB() throws IOException {
//1.1) 获取文本对象
File file = new File("D:/a/a.txt");
//1.2) 定义字符输出流,将字符写入到此文件对象中
FileWriter fw = new FileWriter(file,true);
//1.3)定义字符串
String str = "啊啊啊啊啊,dadaismdsadsads";
//1.4) 将字符串写入到文件对象中
fw.write(str);
//1.5) 刷新流
fw.flush();
//1.6) 关闭流
fw.close();
}
- 读和写操作
/**
* 案例五:将指定文件中内容读取按指定格式输出。[方法一:利用字符串拆分]
* a)testdemo.txt文件自已在F盘下创建,内容如下。D:\a
* 李明|张小林|胡守成
* b)运行结果如下:
* 李明
* 张小林
* 胡守城
* c)提示:通过String类的split(“\\|”)
*/
@Test
public void testC() throws IOException {
//1.1) 先创建文件对象
File file = new File("D:/a/testdemo.txt");
//1.2) 判断是否存在此文件,如果不存在,那么就创建文件
if (!file.exists()){
file.createNewFile();
}
//1.3) 创建文档输出流对象
FileWriter fw = new FileWriter(file);
//1.4) 创建字符串将指定东西添加到文档中
String str = "李明|张小林|胡守成";
//1.5) 将此字符写入到文档中
fw.write(str);
//1.6) 刷新流
fw.flush();
//1.7) 创建文档输入流对象读取文档信息
FileReader fr = new FileReader(file);
//1.8) 将读取到的信息储存到数组中
char[] ch = new char[(int) file.length()];
fr.read(ch);
//1.9) 将数组中的元素转化为字符串
String s = new String(ch);
//1.10) 将字符串按照|号分割
String[] split = s.split("\\|");
for (String s1 : split) {
System.out.println( s1);
}
//1.11) 关闭流
fr.close();
fw.close();
}
(贰):缓冲流流专属
缓冲流其实就是一个自带缓冲功能的包装流,其需要传入一个字节流或者字符流对象,即节点流。一次缓冲流可以储存8kb字节。所以传输速度快。字节关闭缓冲流即可达到关闭节点流的效果,其中字符缓冲流一次可以读取一行。readLine();
①:字节流
- BufferedInputStream
/**
* 使用缓冲流的方式会快很多
*/
@Test
public void testB() throws IOException {
//1.1) 定义文件对象
File f1 = new File("D:\\java学习课程\\Java面试汇总0510.pdf");
File f2 = new File("D:/Java面试汇总0510.pdf");
//1.2)定于字节输入流
FileInputStream fis = new FileInputStream(f1);
//1.3)包装成输入缓冲流
BufferedInputStream bis = new BufferedInputStream(fis);
//1.4) 定义字节输出流
FileOutputStream fos = new FileOutputStream(f2);
//1.5) 包装成缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(fos);
//1.6) 直接用包装流进行读取
int read = 0;
//1.7) 判断是否达到末尾 即 -1
while (!((read = bis.read()) == -1)){
//1.8) 写入到文件中,一次8kb
bos.write(read);
}
//1.9) 关闭流
bis.close();
bos.close();
}
- BufferedOutputStream
②:字符流
字符流的缓冲字符流有一个特有的一次读取一行文件的方法ReadLint()
- BufferedReader
/**
* 案例二:一次读取一行数据,D:\a.txt
* 分析:
* 1.因为要求需要一次读取一行数据,此方法在字符流中才有
* 2.那么多需要定义字符缓冲流
*/
@Test
public void testC() throws IOException {
//1.1) 定义文件对象
File file = new File("D:\\a.txt");
//1.2) 定义文件输入流
FileReader fw = new FileReader(file);
//1.3) 包装输入流
BufferedReader bw = new BufferedReader(fw);
//1.4) 先读出第一行
String s = bw.readLine();
System.out.println("s = " + s);
//1.5) 关闭流
bw.close();
}
我们常常用读取一行的方式用在键盘输入输出流中结合使用,请看标准输入输出流
2. BufferedWriter
(叁):转换流专属(字节流转化为字符流转化器)
①:字节转字符流
多用于字节流转化为字符流做转换器的功能
- InputSreamReader
- OutputStreamWriter
(肆):数据流专属
①:字节流
- DataInputStream
- DataOutputStream
②:字符流
- DataReader
- DataWriter
(伍):对象流专属(序列化和反序列化)
①:字节流下的对象流
此流可以将内存中的对象分割保存到硬盘中,也可以将硬盘中的分割对象组装到内存中。对象流可以传递一个对象(实现可序列化接口Serializable(标记接口),包括属性行为,transient标记的属性是关闭序列化功能…),提供对对象图形的持久存储,很少用,因为有数据库,可以用在模板与模板之间读取调用对象的功能,也可以对集合进行序列化与反序列化
标记接口没有任何内容,JVM遇到这个接口会生成此对象的序列化版本号,版本号用来区分同名类是否是同一个类
- ObjectInputStream----------》组装,反序列化
/**
* 案例二:反序列化学生对象
* 分析:
* 1.定义储存有对象的文件
* 2.创建文本输入流传入文件
* 3.定义反反序列对象将此字节输入流放进去
* 4.调用reader方法将对象一个一个反序列化拿出来
*
*/
@Test
public void testB() throws IOException, ClassNotFoundException {
//2.1) 定义需要反序列化文件对象
File f = new File("D:/aa/b/a.txt");
//2.2) 定义字节输入流
FileInputStream fis = new FileInputStream(f);
//2.3) 定义反徐内化对象
ObjectInputStream ois = new ObjectInputStream(fis);
//2.4) 调用方法将一个个对象拼接出来
for (int i = 0; i < 4; i++) {
//2.5) 强转化为学生对象
Student st = (Student) ois.readObject();
System.out.println(st);
}
//2.6) 关闭流
ois.close();
}
- ObjectOutputStream--------》分割,序列化
public class Test03 {
/**
* 案例一:序列化学生对象
* 分析:
* 1.定义文件对下,即将序列化后的学生对象储存到的文件位置对象
* 2.创建学生对象,并初始化出三个学生对象
* 3.创建序列化对象,ObjectOutputStream(file)
* 4.调用徐内化对象方法将对象一个一个写到文件中
* 5.关闭流
*/
@Test
public void testA() throws IOException {
//1.1) 定义需要储存到的文件对象
File file = new File("D:/aa/b");
file.mkdirs();
File file1 = new File("D:/aa/b/a.txt");
//1.2) 实例化学生对象
Student s1 = new Student(1,"小红","女",18,"美国");
Student s2 = new Student(2,"小白","男",18,"欧洲");
Student s3 = new Student(3,"小绿","女",18,"日本");
Student s4 = new Student(4,"小黑","男",18,"非洲");
//1.3) 定义序列化流,因为它要传入一个字节输出流对象,所以先创建一个直接输出流对象
FileOutputStream fos = new FileOutputStream(file1);
ObjectOutputStream oos = new ObjectOutputStream(fos);
//1.4) 将对象序列化到文件中
oos.writeObject(s1);
oos.writeObject(s2);
oos.writeObject(s3);
oos.writeObject(s4);
//1.5) 关闭流
oos.close();
}
(陆):标准输出流
- PrintWriter
- PrintSream
/**
* 案例三:对键盘输入的每一行写入到新文件中
* 分析:
* 1.我们要将输入的文件写入到文件中储存,并且输入end结束输入
* 2.定义接收键盘数据的输入流,返回的是一个字节输入流
* 3.定义文件对象
* 4.因为需要用到一次输入一行,此时只能调用BufferedReader的方法
* 5.因为包装输出流需要传递的是字符流,那么需要将字节输入流转化为字符流
* 6.将键盘读取到的一行数据放到缓冲流中
* 7.定义标准输出流将缓冲流中的文件写入到指定文件
* 8。关闭
*/
public static void testD() throws IOException {
//1.1) 定义标注字节输入流,获取控制台输入的文件对象
InputStream in = System.in;
//1.2) 定义写入到的位置对象
File f = new File("D:/b.txt");
//1.3) 字节流转为字符流
InputStreamReader isr = new InputStreamReader(in);
//1.4) 包装此字符流
BufferedReader br = new BufferedReader(isr);
//1.5) 定义标准输出流,输出到目标文件
PrintWriter ps = new PrintWriter(f);
String s = "";
//1.6) 判断如果不是end那么就输出到目标文件
while (!"end".equalsIgnoreCase(s)){
s= br.readLine();
//1.7) 输出到目标文件
ps.println(s);
}
//1.8) 关闭流啊
br.close();
ps.close();
}