IO 流学习总结
一:IO 流的概述
1. 什么是 IO 流?
存储和读取数据的解决方法
I:input O:output
流:像水流一样传输数据
2. IO 流的作用?
用于读写数据(本地文件,网络)
3. IO 流按照流向可以分类哪两种流?
输出流:程序 ----> 文件
输入流:文件 ----> 程序
4. IO 流按照操作文件的类型可以分为哪两种流?
字节流:可以操作所有类型的文件
字符流:只能操作纯文本文件
5. 什么是纯文本文件?
用 windows 系统自带的记事本打开并且能读得懂的文件 txt 文件、md 文件、xml 文件、lrc 文件等
6. IO 流基本体系
二:IO 流基本用法
1. 字节流
1.1 fileOutputStream
**作用:**可以把程序中的数据写到本地文件上,是字节流的基本流。
书写步骤
// 1. 创建对象FileOutputStream fos = new FileOutputStream("hmio\\a.txt");// 2. 写入数据fos.write(88);// 3. 释放资源fos.close();
字节输出流书写细节
① 创建字节输出流对象
细节一:参数是字符串表示的路径或者 File 对象都可以
细节二:如果文件不存在会创建一个新文件,但是要保证父级路径是存在的
细节三:如果文件已经存在,则会清空文件
② 写数据
细节:write 方法的参数是整数,但实际上写到本地文件中的是整数在 ASCII 上对应的字符
③ 释放资源
细节:每次使用完之后都要释放资源
如果没有释放资源,那么这个资源 / 文件就会一直被占用着。无法进行删除等操作。
三种写出多个数据的方式
// 1. 创建对象FileOutputStream fos = new FileOutputStream("hmio\\a.txt");// 2. 写出数据// fos.write(97); // a
// fos.write(98); // bbyte[] bytes = {97, 98, 99 ,100, 101};/*fos.write(bytes);*/fos.write(bytes, 1, 2); // b c// 3. 释放资源fos.close();
换行与续写
// 换行与续写// 1. 换行直接写个换行符就好了// 2. 续写在创建 FileOutputStream 的时候开启续写开关 true(默认为 false)// 1. 创建对象FileOutputStream fos = new FileOutputStream("hmio\\a.txt", true);// 2. 写出数据String str = "hello";byte[] bytes = str.getBytes();fos.write(bytes);// 再次写入一个换行符就好了// 换行符:windows:\r\n Linux:\n Mac:\r// Java 中只写 \r 或者 \n 也可以起到换行作用String wrap = "\r\n";byte[] bytes2 = wrap.getBytes();fos.write(bytes2);String str2 = "666";byte[] bytes3 = str2.getBytes();fos.write(bytes3);// 3. 释放资源fos.close();
1.2 fileInputStream
基本用法
// 1. 创建对象FileInputStream fis = new FileInputStream("hmio\\a.txt");// 2. 读取资源int b1 = fis.read();System.out.println((char)b1);// 3. 释放资源fis.close();
FileInputStream 书写细节
① 创建字节输入流对象
细节一:如果文件不存在,就直接报错
② 读取数据
细节二:一次读一个字节。读出来的是数据在 ASCII 上对应的数字
细节二:读到文件末尾了,read 方法返回 -1。
③ 释放资源
细节一:每次使用完必须要释放资源。
循环读取整个文件
// 1. 创建对象FileInputStream fis = new FileInputStream("hmio\\a.txt");// 2. 读取资源int b;while ((b = fis.read()) != -1) {System.out.println((char) b);}// 3. 释放资源fis.close();
3. 文件拷贝
// 1. 创建对象FileInputStream fis = new FileInputStream("D:\\a.txt");FileOutputStream fos = new FileOutputStream("hmio\\copy.txt");// 2. 拷贝int b;while ((b = fis.read()) != -1) {fos.write(b);}// 3. 释放资源// 规则:先开的流最后关闭fos.close();fis.close();
这只适用于小文件的拷贝,如果是大文件的拷贝会相当耗时,因为这个拷贝的方式是每拷贝一个字节建立一次连接,拷贝的文件越大,建立的连接数量越多。
我们可以使用 read(byte[] buffer) 的方法来读取数据,这是一次读取一个字节组的数据,这样就可以做到只需要建立一次连接就可以拷贝一批量的字节。
大文件的拷贝原理:
// 1. 创建对象
FileInputStream fis = new FileInputStream("D:\\a.txt");
// 2. 拷贝
byte[] bytes = new byte[2];
// 一次读取多个字节数据,具体读多少,跟数据的长度有关。
int len = fis.read(bytes);
System.out.println(len);
String str = new String(bytes, 0, len);
System.out.println(str);int len2 = fis.read(bytes);
System.out.println(len2);
String str2 = new String(bytes, 0, len2);
System.out.println(str2);int len3 = fis.read(bytes);
System.out.println(len3);
String str3 = new String(bytes, 0, len3);
System.out.println(str3);
fis.close();
大文件拷贝示例:
// 1. 创建对象
FileInputStream fis = new FileInputStream("D:\\ProMaterisals\\idea\\HMIO\\hmio\\a.txt");
FileOutputStream fos = new FileOutputStream("hmio\\copy2.txt");
// 2. 拷贝
int len;
byte[] bytes = new byte[1024 * 1024 * 5]; // 5m
while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);
}
// 3. 释放资源
fos.close();
fis.close();
利用 try…catch… finally 捕获拷贝文件中代码出现的异常
// 1. 创建对象
FileInputStream fis = null;
FileOutputStream fos = null;
try {fis = new FileInputStream("D:\\ProMaterisals\\idea\\HMIO\\hmio\\a.txt");fos = new FileOutputStream("hmio\\copy2.txt");// 2. 拷贝int len;byte[] bytes = new byte[1024 * 1024 * 5]; // 5mwhile ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}
} catch (IOException e) {e.printStackTrace();
} finally {// 3. 释放资源if (fos != null) {try {fos.close();} catch (IOException e) {e.printStackTrace();}}if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}
}
4. 字符集
ASCII、GBK 详解
1. 在计算机中,任意数据都是以二进制的形式存储的。
2. 计算机中最小的存储单位是一个字节。
3. ASCII 字符集中,一个英文占一个字节。
4. 简体中文版 Windows,默认使用 GBK 字符集。
5. GBK 字符集完全兼容 ASCII 字符集。1. 一个英文占一个字节,二进制第一位是 02. 一个中文占两个字节,二进制高位字节的第一位是 1
Unicode 详解
1. Unicode 字符集的 UTF-8 编码格式1. 一个英文占一个字节,二进制第一位是 0,转成十进制是正数2. 一个中文占三个字节,二进制第一位是 1,第一个字节转成十进制是负数
乱码出现的原因:
1. 使用字节流读取数据的时候未读完整整个汉字(字节流一次读取一个字节)。2. 编码和解码时的方式不统一。
5. 字符流
5.1 FileReader
read (空参)方法详解:
// 1. 创建对象并关联本地文件
FileReader fr = new FileReader("hmio\\a.txt");
// 2. 读取数据
// 字符流的底层也是字节流,默认也是一个字节一个字节的读取的。
// 如果遇到中文就会一次读取多个,GBK 一个读两个字节,UTF-8(IDEA 默认) 一次读取三个字节。// read() 细节:
// 1. read():默认也是一个字节一个字节的读取,如果遇到中文就会一次读取多个
// 2. 在读取之后,方法的底层还会进行解码并转成十进制。
// 最终把这个十进制作为返回值
// 这个十进制的数据也表示在字符集上的数字
// 英文:文件里面二进制的数据 0110 0001
// read 方法进行提取,解码并转成十进制 97
// 中文:文件里面的二进制数据:11100110 10110001 10001001
// read 方法进行提取,解码并转成十进制 27721int ch;
while ((ch = fr.read()) != -1) {System.out.print((char) ch);
}
// 3. 释放资源
fr.close();
read(有参)方法详解
// 1. 创建对象并关联本地文件
FileReader fr = new FileReader("hmio\\a.txt");
// 2. 读取数据
char[] chars = new char[2];
int len;
// read(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数据当中
// 空参 read + 强转类型转换
while ((len = fr.read(chars)) != -1) {// 把数据中的数据编程字符串再打印System.out.println(new String(chars, 0, len));
}
// 3. 释放资源
fr.close();
5.2 FileWriter
书写细节
① 创建字符输出流对象
细节1:参数是字符串表示的路径或者 File 对象都可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件,如果不想被清空可以打开续写
② 写数据
细节:如果 writer 方法的参数是整数,但是实际上写道本地文件中的是整数在字符集上对应的字符
③ 释放资源
细节:每次使用完之后释放资源
5.3 字符流原理解析
缓冲区
① 创建字符输入流对象
底层:关联文件,并创建缓冲区(长度为 8129 的字节数组)
② 读取数据
1.判断缓冲区中是否有数据可以读取
2. 缓冲区中没有数据:就从文件中获取数据,装到缓冲区中,每次尽可能装满缓冲区,如果文件也没有数据,返回 -1
3. 缓冲区有数据:就从缓冲区中读取。
(1) 空参 read 方法:一次读取一个字节,遇到中文一次读多个字节,把字节解码并转成十进制返回
(2) 有参 read 方法:把读取字节,解码,强转三步合并了,强转之后的字节放到数组中
以下验证是否有缓冲区(a 文件中要多于 8129 字节的数据,程序会把存入程序中的数据读取出来,大于 8129 字节的数据无法读取)
FileReader fr = new FileReader("hmio\\a.txt");
fr.read(); // 会把文件中的数据读取到缓冲区// 清空文件
FileWriter fw = new FileWriter("hmio\\a.txt");// 会把缓冲区的数据全部读取完毕
// 但是也只能打印缓冲区中的数据,文件剩余的数据不能被打印出来
int ch;
while ((ch = fr.read()) != -1) {System.out.println((char) ch);
}fw.close();
fr.close();
缓冲区中的数据什么时候会写入目标文件中?
① 缓冲区满了之后
FileWriter fw = new FileWriter("hmio\\a.txt");
for (int i = 0; i < 8193; i++) {fw.write(97);
}
② 执行 flush 或者 close 方法之后
FileWriter fw = new FileWriter("hmio\\a.txt");
fw.write("阿巴1");
fw.write("阿巴2");
fw.write("阿巴3");
fw.flush();
fw.write("阿巴4");
FileWriter fw = new FileWriter("hmio\\a.txt");
fw.write("阿巴4");
fw.write("阿巴5");
fw.write("阿巴6");
fw.write("阿巴7");
fw.close();
flush 跟 close 的区别:
flush 执行完之后可以继续在后面写数据。close 方法执行完之后,连接就断开可。
6. 练习
6.1 拷贝文件夹
public class Test01 {public static void main(String[] args) throws IOException {// 拷贝一个文件夹,考虑子文件夹// 1. 创建对象表示数据源File src = new File("D:\\ProMaterisals\\idea\\HMIO\\testDir");// 2. 创建对象表示目的地File dest = new File("D:\\ProMaterisals\\idea\\HMIO\\testDirCopy");// 调用方法开始拷贝copyDir(src, dest);}/*** 拷贝文件夹* @param src* @param dest*/private static void copyDir(File src, File dest) throws IOException {dest.mkdirs();// 递归// 1. 进入数据源File[] files = src.listFiles();// 2. 遍历数组for (File file : files) {if (file.isFile()) {// 3. 判断文件,拷贝FileInputStream fis = new FileInputStream(file);FileOutputStream fos = new FileOutputStream(new File(dest, file.getName()));byte[] bytes = new byte[1024];int len;while ((len = fis.read(bytes)) != -1) {fos.write(bytes, 0, len);}fos.close();fis.close();} else {// 4. 判断文件夹,递归copyDir(file, new File(dest, file.getName()));}}}
}
6.2 文件加密与解密
加密解密的原理:
在 Java 代码中,当一个数字两次异或(^) 同一个数字的时候,得到的结果是原来那个数字。
System.out.println(100 ^ 10); // 110
System.out.println(110 ^ 10); // 100
FileInputStream fis = new FileInputStream("hmio\\encj.jpg");
FileOutputStream fos = new FileOutputStream("hmio\\redu.jpg");
// 加密处理
int b;
while ((b = fis.read()) != -1) {fos.write(b ^ 2);
}
// 释放资源
fos.close();
fis.close();
解密的时候只需要把已加密的文件重新异或一次加密时异或的数字就好了。
6.3 修改文件中的数据
// 1. 读取数据FileReader fr = new FileReader("hmio\\a.txt");StringBuilder sb = new StringBuilder();int ch;while ((ch = fr.read()) != -1) {sb.append((char) ch);}fr.close();System.out.println(sb);// 排序Integer[] arr = Arrays.stream(sb.toString().split("-")).map(Integer::parseInt).sorted().toArray(Integer[]::new);
// System.out.println(Arrays.toString(arr));FileWriter fw = new FileWriter("hmio\\a.txt");String s = Arrays.toString(arr).replace(", ", "-");s = s.substring(1, s.length() - 1);System.out.println(s);fw.write(s);fw.close();
三:高级流
1. 缓冲流
1.1 字节缓冲流拷贝文件
字节缓冲流创建的时候也会创建一个长度为 8192 的缓冲区
一次读取单个字节
// 1. 创建缓冲流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("hmio\\a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("hmio\\copy.txt"));
// 2. 循环读取并写道目的地
int b;
while ((b = bis.read()) != -1) {bos.write(b);
}
// 3. 释放资源
bos.close();
bis.close();
一次读取多个字节
// 1. 创建缓冲流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("hmio\\a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("hmio\\copy2.txt"));
// 2. 拷贝
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1) {bos.write(bytes, 0, len);
}
// 3. 释放资源
bos.close();
bis.close();
1.2 字符缓冲流
输入
// 1. 创建缓冲流对象
BufferedReader br = new BufferedReader(new FileReader("hmio\\a.txt"));
// 2. 读取数据
// readLine 方法一次会读取一整行,遇到回车换行结束
// 但是它不会把回车换行读取到内存当中
/*String line = br.readLine();
System.out.println(line);*/
String line;
while ((line = br.readLine()) != null) {System.out.println(line);
}
br.close();
输出
BufferedWriter bw = new BufferedWriter(new FileWriter("hmio\\b.txt", true));
bw.write("123");
bw.newLine();
bw.write("456");
bw.newLine();
bw.close();
缓冲流总结
1. 缓冲流有几种?1. 字节缓冲输入流:BufferedInputStream2. 字节缓冲输出流:BufferedOutputStream3. 字节缓冲输入流:BufferedReader4. 字节缓冲输出流:BufferedWriter
2. 缓冲流为什么能提高性能?1. 缓冲流自带长度为 8192 的缓冲区2. 可以显著提高字节流的读写性能3. 对于字符流提升不显著,对于字符缓冲流而言关键点是两个特有的方法3. 字符缓冲流两个特有的方法是什么?4. 字符缓冲输入流 BufferedReader:readLine() (一次读取一行2. 字符缓冲输出流 BufferedWriter:newLine() (换行,可跨平台使用
缓冲流综合练习
对文件中的首列序号进行排序
8.愿陛下托臣以讨贼兴复之效,不效,则治臣之罪,以告先帝之灵。若无兴德之言,则责攸之、祎、允等之慢,以彰其咎;陛下亦宜自谋,以咨诹善道,察纳雅言,深追先帝遗诏,臣不胜受恩感激。
3.侍中、侍郎郭攸之、费祎、董允等,此皆良实,志虑忠纯,是以先帝简拔以遗陛下。愚以为宫中之事,事无大小,悉以咨之,然后施行,必能裨补阙漏,有所广益。
4.将军向宠,性行淑均,晓畅军事,试用于昔日,先帝称之曰能,是以众议举宠为督。愚以为营中之事,悉以咨之,必能使行阵和睦,优劣得所。
2.宫中府中,俱为一体,陟罚臧否,不宜异同。若有作奸犯科及为忠善者,宜付有司论其刑赏,以昭陛下平明之理,不宜偏私,使内外异法也。
1.先帝创业未半而中道崩殂,今天下三分,益州疲弊,此诚危急存亡之秋也。然侍卫之臣不懈于内,忠志之士忘身于外者,盖追先帝之殊遇,欲报之于陛下也。诚宜开张圣听,以光先帝遗德,恢弘志士之气,不宜妄自菲薄,引喻失义,以塞忠谏之路也。
9.今当远离,临表涕零,不知所言。
6.臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯。先帝不以臣卑鄙,猥自枉屈,三顾臣于草庐之中,咨臣以当世之事,由是感激,遂许先帝以驱驰。后值倾覆,受任于败军之际,奉命于危难之间,尔来二十有一年矣。
7.先帝知臣谨慎,故临崩寄臣以大事也。受命以来,夙夜忧叹,恐托付不效,以伤先帝之明,故五月渡泸,深入不毛。今南方已定,兵甲已足,当奖率三军,北定中原,庶竭驽钝,攘除奸凶,兴复汉室,还于旧都。此臣所以报先帝而忠陛下之职分也。至于斟酌损益,进尽忠言,则攸之、祎、允之任也。
5.亲贤臣,远小人,此先汉所以兴隆也;亲小人,远贤臣,此后汉所以倾颓也。先帝在时,每与臣论此事,未尝不叹息痛恨于桓、灵也。侍中、尚书、长史、参军,此悉贞良死节之臣,愿陛下亲之信之,则汉室之隆,可计日而待也。
/*** 将乱序的《出师表》进行排序*/// 1. 读取数据BufferedReader br = new BufferedReader(new FileReader("hmio\\csb.txt"));String line;TreeMap<Integer, String> tm = new TreeMap<>();while ((line = br.readLine()) != null) {String[] arr = line.split("\\.");tm.put(Integer.parseInt(arr[0]), arr[1]);}br.close();
// System.out.println(tm);// 2. 写出数据BufferedWriter bw = new BufferedWriter(new FileWriter("hmio\\result.txt"));Set<Map.Entry<Integer, String>> entries = tm.entrySet();for (Map.Entry<Integer, String> entry : entries) {String value = entry.getValue();bw.write(value);bw.newLine();}bw.close();
2. 转换流
转换流是字符流和字节流之间的桥梁
2.1 转换流读取与写出数据
利用转换流按照指定的字符编码读取数据
/*// 1. 创建对象并指定字符编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("hmio\\gbkfile.txt"), "GBK");
// 2. 读取数据
int ch;
while ((ch = isr.read()) != -1) {System.out.println((char) ch);
}
// 3. 释放资源
isr.close();*//*** 需要使用 JDK11+*/
FileReader fr = new FileReader("hmio\\\\gbkfile.txt", Charset.forName("GBK"));
// 2. 读取数据
int ch;
while ((ch = fr.read()) != -1) {System.out.println((char) ch);
}
// 3. 释放资源
fr.close();
利用转换流按照指定字符编码写出
/*** 利用转换流按照指定字符编码写出*/
/*// 1. 创建转换流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("hmio\\b.txt"), "GBK");
// 2. 写出数据
osw.write("你好你好");
// 3. 关闭连接
osw.close();*//*** 替代方案 JDK11 +*/
FileWriter fw = new FileWriter("hmio\\c.txt", Charset.forName("GBK"));
fw.write("你好你好");
fw.close();
转换流练习
使用转换流将读取的 GBK 文件转换为 UTF-8
/*** 将本地文件中的 GBK 文件,转换成 UTF-8*/
// 1. JDK11 以前的方案
/*InputStreamReader isr = new InputStreamReader(new FileInputStream("hmio\\b.txt"), "GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("hmio\\d.txt"), "UTF-8");int b;
while ((b = isr.read()) != -1) {osw.write(b);
}*/// 2. 替代方案
FileReader fr = new FileReader("hmio\\b.txt", Charset.forName("GBK"));
FileWriter fw = new FileWriter("hmio\\e.txt", Charset.forName("UTF-8"));
int b;
while ((b = fr.read()) != -1) {fw.write(b);
}
fw.close();
fr.close();
利用字节流读取文件的数据,每次读取一整行,而且不能乱码
/*** 利用字节流读取文件的数据,每次读取一整行,而且不能乱码** 1. 字节流读取中文的时候,是会出现乱码的,但是字符流可以搞定* 2. 字节流里面是没有读取一整行的方法的,只有字符缓冲流可以搞定*/
// FileInputStream fis = new FileInputStream("hmio\\a.txt");
// InputStreamReader isr = new InputStreamReader(fis);
// BufferedReader br = new BufferedReader(isr);
//
// String str = br.readLine();
// System.out.println(str);
//
// br.close();BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("hmio\\a.txt")));String line;while ((line = br.readLine()) != null) {System.out.println(line);}br.close();
转换流总结
1. 转换流名字1. 字符转换输入流:InputStreamReader2. 字符转换输入流:OuputStreamWriter
2. 转换流的作用:1. 指定字符集读写数据(JDK11 之后就被淘汰)2. 字节流想要使用字符流中的方法了
3. 序列化流
3.1 序列化流读取/输出对象
序列化流写出对象
/*** 利用序列化流/对象操作流,把一个对象写到本地中*/
// 1. 创建对象
Student stu = new Student("zhangsan", 10);
// 2. 创建序列化流的对象/对象操作输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hmio\\a.txt"));
// 3. 写出数据
oos.writeObject(stu);
// 4. 释放资源
oos.close();
反序列化流读取对象
/*** 利用反序列化流,把文件中的对象读取到程序中。*/
// 1. 创建反序列化流的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hmio\\a.txt"));
// 2. 读取数据
Object o = ois.readObject();
System.out.println(o);
// 3. 释放资源
ois.close();
3.2 序列化流细节汇总
-
使用序列化流将对象写道文件时,需要让 Javabean 类实现 Serializable 接口。否则,会出现 NotSerializableException 异常。
-
序列化流写到文件中的数据不能修改,一旦修改就无法再次读回来了。
-
序列化对象后,修改了 Javabean 类,再次反序列化,会不会有问题?
会出问题,会抛出 InvalidClassException 异常。
解决方案:给 Javabean 类添加 serialVersionUID(序列号、版本号)
- 如果一个对象的某个成员变量的值不想被序列化,又如何实现?
解决方案:给该成员变量加 transient 关键字修饰,该关键字标记的成员变量不参与序列化过程。
序列化流练习
序列化读写多个对象
序列化的 Javabean 对象:Student.java
import java.io.Serializable;public class Student implements Serializable {private static final long serialVersionUID = -7424513845312147863L;private String name;private int age;private String address;public Student() {}public Student(String name, int age, String address) {this.name = name;this.age = age;this.address = address;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", address='" + address + '\'' +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}
}
序列化写出对象
/*** 将多个自定义对象序列化到文件中,但是对象的个数不确定,该如何操作呢?*/
// 1. 序列化多个对象
Student s1 = new Student("zhangsan", 12, "魔都");
Student s2 = new Student("lisi", 13, "帝都");
Student s3 = new Student("wangwu", 14, "妖都");ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hmio\\a.txt"));
oos.writeObject(list);oos.close();
序列化读取对象
// 1. 创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hmio\\a.txt"));// 2. 读取数据
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
for (Student student : list) {System.out.println(student);
}// 3. 释放资源
ois.close();
4. 打印流
打印流
分类:打印流一般是指:PrintStream,PrintWriter 两个类
特点一:打印流只操作文件目的地,不操作数据源
特点二:特有的写出方法可以实现,数据原样写出
例如:打印:97 文件中:97
特点三:特有的写出方法,可以实现自动刷新,自动换行
打印一次数据 = 写出 + 换行 + 刷新
4.1 字节打印流
字节打印流底层没有缓冲区
// 1. 创建字节打印流对象
PrintStream ps = new PrintStream(new FileOutputStream("hmio\\a.txt"), true, "UTF-8");
ps.println(97); // 写出 + 自动刷新 + 自动换行
ps.print(true);
ps.println();
ps.printf("%s爱上了%s", "阿珍","阿强");
ps.close();
4.2 字符打印流
字节打印流底层有缓冲区,想要自动刷新需要开启
// 1. 创建字符打印流对象
PrintWriter pw = new PrintWriter(new FileWriter("hmio\\a.txt"), true);
// 2. 写出数据
pw.println("你今天终于叫我名字了,虽然叫错了,但是没关系,我马上改");
pw.print("你好你好");
pw.printf("%s爱上了%s", "阿珍","阿强");
// 3. 释放资源
pw.close();
打印流小结
打印流有几种?各有什么特点?
有字节打印流和字符打印流两种。
打印流不操作数据源,只能操作目的地。
字节打印流:默认自动刷新,特有的 println 自动换行。
5. 解压缩流
5.1 解压流
public static void main(String[] args) throws IOException {// 1. 创建一个 File 表示要解压的压缩包File src = new File("D:\\ProMaterisals\\idea\\HMIO\\testZip.zip");// 2. 创建一个 File 表示要解压的目的地File dest = new File("D:\\ProMaterisals\\idea\\HMIO\\");unzip(src, dest);
}/*** 解压的方法* @param src 要解压的压缩包地址* @param dest 要解压的目的地地址*/
public static void unzip(File src, File dest) throws IOException {// 创建一个解压缩流ZipInputStream zip = new ZipInputStream(new FileInputStream(src));// 先获取到压缩包里面的每一个 zipentry 对象// 表示当前在压缩包当中获取到的文件或者文件夹ZipEntry entry;while ((entry = zip.getNextEntry()) != null) {System.out.println(entry);if (entry.isDirectory()) {// 文件夹:需要在目的地 dest 处创建一个相同的文件夹File file = new File(dest, entry.toString());file.mkdirs();} else {// 文件:需要读取到压缩包中的文件,并把它存放在目的地 dest 文件夹中(按照层级目录进行存放)FileOutputStream fos = new FileOutputStream(new File(dest, entry.toString()));int b;while ((b = zip.read()) != -1) {// 写到目的地fos.write(b);}fos.close();// 表示在压缩包中的文件处理完毕了zip.closeEntry();}}zip.close();
}
5.2 压缩流
压缩单个文件
public class ZipStreamDemo2 {public static void main(String[] args) throws IOException {/*** 压缩流**/// 1. 创建 File 对象表示要压缩的文件File src = new File("D:\\ProMaterisals\\idea\\HMIO\\ziptest.txt");// 2. 创建 File 对象表示压缩包的位置File dest = new File("D:\\ProMaterisals\\idea\\HMIO\\");// 3. 调用方法压缩toZip(src, dest);}/*** 压缩文件* @param src 要压缩的文件* @param dest 压缩包的位置*/public static void toZip(File src, File dest) throws IOException {// 1. 创建压缩流,关联压缩包ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest, "ziptest.zip")));// 2. 创建 ZipEntry 对象,表示压缩包里面的每一个文件和文件夹// 参数:压缩包里面的路径ZipEntry entry = new ZipEntry("ziptest.txt");// 3. 把 ZipEntry 对象放到压缩包中zos.putNextEntry(entry);// 4. 把 src 文件中的数据写到压缩包当中FileInputStream fis = new FileInputStream(src);int b;while ((b = fis.read()) != -1) {zos.write(b);}zos.closeEntry();zos.close();}
}
public class ZipStreamDemo3 {public static void main(String[] args) throws IOException {/*** 把文件夹压缩成一个压缩包*/// 1. 创建 File 对象表示要压缩文件夹的File src = new File("D:\\ProMaterisals\\idea\\HMIO\\testZip1");// 2. 创建 File 对象表示压缩包放在那里File destParent = src.getParentFile(); // src 的 testZip 文件的父级目录// 3. 创建 File 文件表示压缩包的路径File dest = new File(destParent, src.getName() + ".zip");// 4. 创建压缩流关联压缩包ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));// 5. 获取 src 里面的每个文件toZip(src, zos, src.getName());// 6. 释放资源zos.close();}/*** 获取 src 的每个文件,变成 ZipEntry 对象,放入压缩包中* 但是这个方法目前有 BUG,如果要压缩的文件夹里面没有文件,不会被压缩进压缩包* @param src 数据源* @param zos 压缩流* @param name 压缩包内部的路径*/public static void toZip(File src, ZipOutputStream zos, String name) throws IOException {// 1. 进入 src 方法File[] files = src.listFiles();// 2. 遍历数据for (File file : files) {if (file.isFile()) {// 3.判断-文件,变成 ZipEntry 对象,放入压缩包中ZipEntry entry = new ZipEntry(name + "\\" + file.getName());zos.putNextEntry(entry);// 读取文件中的数据,写道压缩包中FileInputStream fis = new FileInputStream(file);int b;while ((b = fis.read()) != -1) {zos.write(b);}fis.close();zos.closeEntry();} else {// 4. 判断-文件夹,递归toZip(file, zos, name + "\\" + file.getName());}}}
}
相关文章:

IO 流学习总结
一:IO 流的概述 1. 什么是 IO 流? 存储和读取数据的解决方法 I:input O:output 流:像水流一样传输数据 2. IO 流的作用? 用于读写数据(本地文件,网络) 3. IO 流按…...

PowerToys——免费、强大、高效的微软官方效率提升工具集,办公学习宝藏软件
名人说:博观而约取,厚积而薄发。——宋苏轼 Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、简单介绍1、PowToys是什么?2、它的功能有哪些?二、下载安装三、功能示例1、始终置顶2、唤醒3、颜色选取器(取色)4、FancyZones(窗口布局)5、File Locksmith6、…...

【C++】 类基础汇总(类封装,构造、析构函数...)
目录 前言 正文 类封装 为什么要进行类封装 概念 访问修饰符 构造函数 概念 特点 析构函数 概念 特点 再谈面向过程与面向对象 面向过程 代码举例 面向对象 代码举例 结语 下期预告 前言 在学习过【C语言进阶C】 C基础--让你丝滑的从C语言进阶到C 之后&am…...

BM61-矩阵最长递增路径
题目 给定一个 n 行 m 列矩阵 matrix ,矩阵内所有数均为非负整数。 你需要在矩阵中找到一条最长路径,使这条路径上的元素是递增的。并输出这条最长路径的长度。 这个路径必须满足以下条件: 对于每个单元格,你可以往上ÿ…...

selenium——unittest框架
目录 一、unittest框架基本介绍二、unittest框架解析三、unittest框架使用方法1.测试固件2.测试套件3.用例的执行顺序4.忽略测试用例中的方法5.unittest断言6.HTML报告生成 一、unittest框架基本介绍 在进行selenium IDE脚本录制导出的脚本中,我们发现其中多了很多…...

matlab频谱分析详解
频谱分析是一种用于分析信号频率特征的方法,常用于信号处理、音乐分析、谐波产生等领域。MATLAB是一种功能强大的数字信号处理软件,提供了许多用于频谱分析的函数和工具箱。 本文将介绍如何使用MATLAB进行频谱分析,包括信号预处理、选择合适…...

用layui写用户登录页面遇到的问题
用layui写用户登录页面遇到的问题 1.在layui-row下面的layui-col-md还是换行 原因:link标签和script标签中的type属性没写,导致应该是script或者这个css没有识别出来 解决办法:link标签里面加上type为text/css, script标签中加上type为 2…...

NMOS双向转换电路实测以及上升沿尖峰处理
NMOS双向转换电路实测以及上升沿尖峰处理 NMOS双向转换电路 🔧采用的是5V供电的STC8H单片机输出PWM波形,经过上面的电平转换电路测量低压端的波形。 ✨在做3.3V <>5V 电平转换电路方案验证时,输入5V PWM波形和输出波形的波形上升沿有尖…...

【数据结构】选择排序(详细)
选择排序 1. 直接选择排序2. 堆排序2.1 堆2.2 堆的实现(以大根堆为例)2.3 堆排序 3. 堆排序(topK问题) 1. 直接选择排序 思想 以排升序为例。以a[i]为最大值(或最小值),从a[i1]到a[n-1-i]比较选…...

什么是企业内容管理?
为什么出现企业内容管理? 在数字经济的宏观背景下,企业建立了各种应用系统以满足企业各业务的管理需求,这些系统每天都在产生大量的数据和信息资源,但在企业实践中存在很多数据或资源无法被应用系统获取、处理和共享。 比如发票…...

机器学习:分类、回归、决策树
分类:具有明确的类别 如:去银行借钱,会有借或者不借的两种类别 回归:不具有明确的类别和数值 如:去银行借钱,预测银行会借给我多少钱,如:1~100000之间的一个数值 不纯度࿱…...

java常见的异常,下一篇写如何正确处理异常
当我们编写Java程序时,经常会遇到各种异常情况。异常是指在程序执行过程中发生的一些错误或意外情况,它会打断程序的正常执行流程,并且需要被适当地处理。在Java中,异常被分为两种类型:可检查异常(Checked …...

C#开发的OpenRA游戏之网络协议打包和解包
C#开发的OpenRA游戏之网络协议打包和解包 OpenRA游戏里,由于这是一个网络游戏,那么与服务器通讯就缺少不了, 既然要通讯,那么就需要协议,有协议就需要对数据进行打包和解包, 这个过程其实就是序列化与反序列化的过程。 游戏里很多命令都需要发送给服务器,以便服务器同…...

K8S通过Ansible安装集群
K8S通过Ansible安装集群 K8S集群安装可参考https://gitee.com/open-hand/kubeadm-ha.git、https://github.com/easzlab/kubeasz.git 安装高可用集群 git clone https://gitee.com/open-hand/kubeadm-ha.git && cd kubeadm-ha升级内核,非必需,默认不升级&…...

ChatGPT辩证观点:“人才不是一个企业的核心竞争力,对人才的管理能力才是一个企业的核心竞争力”
一、问: “人才不是一个企业的核心竞争力,对人才的管理能力才是一个企业的核心竞争力”这句话的理解和误解,这句话有哪个中心论点转移和变化 二、ChatGPT答: 这句话的理解和误解: 理解:这句话的意思是说…...

windows11 永久关闭windows defender的方法
1、按键盘上的windows按键,再点【设置】选项。 2、点击左侧菜单的【隐私和安全性】,再点击列表的【Windows安全中心】选项。 3、点击界面的【病毒和威胁保护】设置项。 4、病毒保护的全部关闭 5、别人的图(正常是都开着的) 6、终极…...

继承的基本知识
概念 假设基于A类,创建了B类,那么称A为B的父类,B为A的子类 子类会继承父类的成员变量及成员函数,但是不能继承构造、析构、运算符重载 假设又基于B创建了C,那么称B为C的直接基类,A为C的间接基类 继承按…...

【Frida-实战】EA游戏平台的文件监控(PsExec.exe提权)
▒ 目录 ▒ 🛫 问题描述环境 1️⃣ 代码编写开源代码搜索自己撸代码procexp确定句柄对应的文件名并过滤 2️⃣ PsExec.exe提权定位找不到EABackgroundService.exe的问题 PsExec.exe提权PsExec.exe原理 🛬 结论📖 参考资料 🛫 问题…...

可视化和回归分析星巴克咖啡在中国的定价建议
可视化和回归分析星巴克咖啡在中国的定价建议。星巴克的拿铁大杯Tall 在各国的价格。 Claude AI | 代码自动生成的数据可视化代码 选择Claude AI 而非 ChatGPT的理由是前者更懂中文!具体可以参见我前面的两篇文章对比两者的中英文翻译的表现及使用安装等难易程度…...

热门影片怎么买票比较便宜,低价买电影票的方法,纯攻略!
有时候真的有被自己蠢到!看电影看了这么多年,竟然不知道电影票价格才9.9元、19.9元就能买到。之前我看电影动不动就是几十上百块,感觉好亏啊。 其实,我也不敢相信的,通过这些平台,同时在节假日甚至春节档期…...

Python通过SWIG调用C++时出现的ImportError问题解析
摘要 win10系统,编译器为mingw,按照教程封装C的一个类并用python调用,一步步进行直到最后一步运行python代码时,在python代码中import example时报错ImportError: DLL load failed while importing _example: The specified modul…...

3ds Max云渲染有多快,3ds Max云渲染怎么用?
本地渲染效果图和动画3D项目是一个非常耗时的过程,当在场景中使用未优化的几何体或在最终渲染中使用大量多边形模型时,诸如此类的变量最终会增加渲染项目所需的时间和处理器能力。随着提供的渲染服务的云渲染平台出现,越来越多动画师、艺术家…...

Java之线程安全
目录 一.上节回顾 1.Thread类常见的属性 2.Thread类中的方法 二.多线程带来的风险 1.观察线程不安全的现象 三.造成线程不安全现象的原因 1.多个线程修改了同一个共享变量 2.线程是抢占式执行的 3.原子性 4.内存可见性 5.有序性 四.解决线程不安全问题 ---synchroni…...

我有一个方法判断你有没有编程天赋
我有一个方法判断你有没有编程天赋 一 前言 基于知识的诅咒的原理 做一个敲击者很难。问题在于敲击者已拥有的知识(歌曲题目)让 他们想象不到缺乏这种知识会是什么情形。当他们敲击的时候,他 们不能想象听众听到的是那些独立的敲击声而不是…...

python 生成chart 并以附件形式发送邮件
import requests import json import pandas as pd import numpy as np import matplotlib.pyplot as plt data np.random.randn(5, 3)#生成chart def generate_line_chart(data):df pd.DataFrame(np.abs(data),index[Mon, Tue, Wen, Thir, Fri],columns[A, B, C])df.plot()…...

leetcode-035-搜索插入位置
题目及测试 package pid035; /*35. 搜索插入位置 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。请必须使用时间复杂度为 O(log n) 的算法。示例 1:输入: nums …...

读书笔记--数据治理之法
继续延续上一篇文章,对数据治理之法进行学习。数据治理之法是战术层面的方法,是一套涵盖8项举措的数据治理实施方法论,包括梳理现状与确定目标、能力成熟度评估、治理路线图规划、保障体系建设、技术体系建设、治理策略执行与监控、绩效考核与…...

送了老弟一台 Linux 服务器,它又懵了!
大家好,我是鱼皮。 前两天我学编程的老弟小阿巴过生日,我问他想要什么礼物。 本来以为他会要什么游戏机、Q 币卡、鼠标键盘啥的,结果小阿巴说:我想要一台服务器。 鱼皮听了,不禁称赞道:真是个学编程的好苗…...

CentOS 7(2009) 升级 GCC 版本
1. 前言 CentOS 7 默认安装的 gcc 版本为 4.8,但是很多时候都会需要用到更高版本的 gcc 来编译源码,那么本文将会介绍如何在线升级 CentOS 的 gcc 版本。 2. 升级 GCC (1). 安装 centos-release-scl; [imaginemiraclecentos7 ~]$ sudo yum…...

java非静态代码块和静态代码块介绍
代码块 SE.10.0…02.28 非静态普通代码块:定义在方法内部的代码块,不用任何关键字修饰,又名构造代码块、实例代码块 静态代码块:用static修饰的代码块 非静态代码块 public class Test {public static void main(String[] args…...