IO 目录
- 一、IO流的概述
- IO流的分类
- 二、基本流
- 2.1字节流
- 2.2 字节输出流写出数据的三种方式
- 2.3 换行和续写
- 2.4 字节输入流
- 2.5 文件拷贝
- 2.6 IO流中不同JDK版本捕获异常的方式
- 2.7 字符集详解
- 2.7.1 ASCII字符集
- 2.7.2 GBK字符集
- 2.7.3 Unicode字符集
- 2.8 为什么会有乱码
- 2.9 Java中的编码和解码
- 2.10 字符流
- FileReader
- FileWriter
- 字符流原理解析
- 2.11 综合练习
- 练习1:(拷贝)
- 练习2:(文件加密)
- 练习3:(修改文件中的数据)
- 三、高级流
- 3.1 缓冲流
- 3.1.1 字节缓冲流
- 3.1.2 字符缓冲流
- 3.2 综合练习
- 练习1(拷贝文件)
- 练习2(修改文本顺序)
- 练习3(软件运行次数)
- 3.3 转换流
- 3.4 序列化流
- 3.5 反序列化流
- 3.6 打印流
- 3.7 解压缩流 / 压缩流
- 3.7.1 解压缩流
- 3.7.2 压缩流
- 3.8 Commons-io
- 1,IOUtils(数据相关)
- 拷贝方法:
- 拷贝大文件的方法:
- 将输入流转换成字符串
- 将输入流转换成字符数组
- 字符串读写
- 从一个流中读取内容
- 把数据写入到输出流中
- 从一个流中读取内容,如果读取的长度不够,就会抛出异常
- 比较
- 其他方法
- 2,FileUtils(文件/文件夹相关)
- 复制文件夹
- 复制文件
- 把字符串写入文件
- 把字节数组写入文件
- 把集合里面的内容写入文件
- 往文件里面写内容
- 文件移动
- 清空和删除文件夹
- 创建文件夹
- 获取文件输入/输出流
- 读取文件
- 测试两个文件的修改时间
- 文件/文件夹的迭代
- 其他
- FilenameUtils(文件名/后缀名相关)
- Hutool工具包
一、IO流的概述
IO流:存储和读取数据的解决方方案
内存:不能永久化存储,程序停止,数据丢失
IO流的分类
二、基本流
2.1字节流
public static void main(String[] args) throws IOException {
//实现需求:写出一段文字到本地文件中。(暂时不写中文)
//0.创建字节输出流对象
FileOutputStream fop = new FileOutputStream("day28_code/src/myIO/a.txt");
//1.写数据
fop.write(97);
//2.释放资源
fop.close();
}
字节输出流的细节:
- 创建字节输出流对象
- 细节1:参数是字符串表示的路径或者是File对象都是可以的
- 细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
- 细节3:如果文件已经存在,则会清空文件
2.写数据 - 细节:write方法的参数是整数,但是实际上写到本地文件中的整数在ASCII上对应的字符
- 释放资源
- 每次使用完流之后都要释放资源
2.2 字节输出流写出数据的三种方式
public static void main(String[] args) throws IOException {
//0.创建对象
FileOutputStream fos = new FileOutputStream("day28_code/src/myIO/a.txt");
//1.写出数据
/*fos.write(97);
fos.write(98);*/
byte[] bytes = {97, 98, 100, 101, 102, 103};
// fos.write(bytes);
fos.write(bytes, 1, 3);
//2.释放资源
fos.close();
}
2.3 换行和续写
public static void main(String[] args) throws IOException {
//0.创建对象
FileOutputStream fos = new FileOutputStream("day28_code/src/myIO/a.txt",true);//append 续写开关
//1.写出数据
String str = "Javachengxuyuan";
byte[] bytes1 = str.getBytes();
fos.write(bytes1);
//换行
/*再次写出一个换行符就可以了
* Windows: \r\n
* Linux: \n
* Mac: \r
*
* 细节:
* 在Windows操作系统当中,Java对回车换行进行了优化
* 虽然完整的是\r\n,但是我们写其中一个\r或者\n,
* Java也可以实现换行,因为Java在底层会补全*/
String wrap = "\r\n";
byte[] bytes2 = wrap.getBytes();
fos.write(bytes2);
String str2 = "666";
byte[] bytes3 = str2.getBytes();
fos.write(bytes3);
//2.释放资源
fos.close();
}
2.4 字节输入流
public static void main(String[] args) throws IOException {
//0.创建对象
FileInputStream fis = new FileInputStream("day28_code/src/myIO/a.txt");
//1.读取数据
int b1 = fis.read();
System.out.println((char) b1);
//2.释放资源
fis.close();
}
字节输入流的细节:
- 创建字节输入流对象
- 细节:如果文件不存在,就直接报错
- 写数据
- 细节1:依次读一个字节,读出来的是数据在ASCII上对应的数字
- 细节2:读到文件末尾了,read方法返回-1
- 释放资源
- 细节:每次使用完流时候都要释放资源
public static void main(String[] args) throws IOException {
//0.创建对象
FileInputStream fis = new FileInputStream("day28_code/src/myIO/a.txt");
//1.循环读取
int b;
while ((b = fis.read()) != -1){
System.out.print((char)b);
}
//2.释放资源
fis.close();
}
2.5 文件拷贝
public static void main(String[] args) throws IOException {
//0.创建对象
FileInputStream fis = new FileInputStream("E:\\下载\\123.mp4");
FileOutputStream fos = new FileOutputStream("day28_code/src/myIO/abc.mp4");
//1.拷贝
long start = System.currentTimeMillis();
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
long end = System.currentTimeMillis();
System.out.println(end - start);//统计时间
//2.释放资源
fos.close();
fis.close();
}
public static void main(String[] args) throws IOException {
//0.创建对象
FileInputStream fis = new FileInputStream("day28_code/src/myIO/a.txt");
//读取数据
//一次读3个
byte[] bytes = new byte[3];
int len = fis.read(bytes);
System.out.println(len);
String str = new String(bytes);
System.out.println(str);
//释放资源
fis.close();
}
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
//0.创建对象
FileInputStream fis = new FileInputStream("E:\\下载\\123.mp4");
FileOutputStream fos = new FileOutputStream("day28_code/src/myIO/copy.mp4");
//1.拷贝数据
int len;
byte[] bytes = new byte[5 * 1024 * 1024];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
//2.释放资源
fos.close();
fis.close();
long end = System.currentTimeMillis();
System.out.println(end - start);
}
2.6 IO流中不同JDK版本捕获异常的方式
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//0.创建对象
fis = new FileInputStream("E:\\下载\\123.mp4");
fos = new FileOutputStream("day28_code/src/myIO/copy.mp4");
//1.拷贝数据
int len;
byte[] bytes = new byte[5 * 1024 * 1024];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//2.释放资源
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
简化代码:
JDK7:
public static void main(String[] args) {
/*JDK7 IO流中捕获异常的方法*/
try(FileInputStream fis = new FileInputStream("E:\\下载\\123.mp4");
FileOutputStream fos = new FileOutputStream("day28_code/src/myIO/copy.mp4")){
int len;
byte[] bytes = new byte[5 * 1024 * 1024];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
}catch (IOException e){
e.printStackTrace();
}
}
JDK8:
public static void main(String[] args) throws FileNotFoundException {
/*JDK9 IO流中捕获异常的方法*/
FileInputStream fis = new FileInputStream("E:\\下载\\123.mp4");
FileOutputStream fos = new FileOutputStream("day28_code/src/myIO/copy.mp4");
try (fis; fos) {
int len;
byte[] bytes = new byte[5 * 1024 * 1024];
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.7 字符集详解
字节:计算机最小的存储单元
2.7.1 ASCII字符集
2.7.2 GBK字符集
2.7.3 Unicode字符集
2.8 为什么会有乱码
原因1:读取数据时未读完整个汉字。
原因2:编码和解码时的方式不统一。
2.9 Java中的编码和解码
public static void main(String[] args) throws UnsupportedEncodingException {
//0.编码
String str = "ai你哟";
byte[] bytes1 = str.getBytes(); // UTF-8
System.out.println(Arrays.toString(bytes1)); //[97, 105, -28, -67, -96, -27, -109, -97]
byte[] bytes2 = str.getBytes("GBK");
System.out.println(Arrays.toString(bytes2)); //[97, 105, -60, -29, -45, -76]
//1.解码
String str2 = new String(bytes1); // 平台默认方式
System.out.println(str2); //ai你哟
String str3 = new String(bytes1, "GBK");
System.out.println(str3); //ai浣犲摕
}
2.10 字符流
FileReader
- 空参的方法读取数据:
public static void main(String[] args) throws IOException {
//0.创建对象
FileReader fr = new FileReader("day28_code/src/MyFileStream/a.txt");
//1.读取数据
/*read() 细节:
* 1.read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个
* 2.在读取之后,方法的底层还会进行解码并转成十进制
* 最终把这个十进制作为返回值
* 这个十进制的数据也表示在字符集上的数字*/
int ch = 0;
while ((ch = fr.read())!=-1){
System.out.print((char) ch);
}
//2.释放资源
fr.close();
}
- 带参方法读取数据
public static void main(String[] args) throws IOException {
//0.创建对象
FileReader fr = new FileReader("day28_code/src/MyFileStream/a.txt");
//1.读取数据
char[] chars = new char[2];
int len;
while ((len = fr.read(chars)) != -1) {
System.out.print(new String(chars, 0, len));
}
//2.释放资源
fr.close();
}
- read(chars):读取数据,解码,强转三步合并了,把强转 之后的字符房嫂数组当中
- 空惨的read + 强转类型转换
FileWriter
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("day28_code/src/MyFileStream/b.txt", true);
//写出一个字符
// fw.write(25105);
//写出一个字符串
// fw.write("程序员");
//写出一个字符串的一部分
// fw.write("Java程序员很牛",0,7);
//写出一个字符数组
/*char[] chars = {'a', 'b', 'c'};
fw.write(chars);*/
//写出字符数组的一部分
fw.write("\r\n");
char[] chars = {'a', 'b', 'c'};
fw.write(chars, 1, chars.length - 1);
fw.close();
}
字符流原理解析
2.11 综合练习
练习1:(拷贝)
需求:
拷贝一个文件夹,考虑子文件夹
public static void main(String[] args) throws IOException {
//0.创建对象
File src = new File("day28_code\\src\\MyTest\\src");
File dest = new File("day28_code\\src\\MyTest\\dest");
//1.调用方法copy
copyDir(src,dest);
}
/*作用:拷贝文件
* 参数一:要拷贝的文件(数据源)
* 参数二:目的地*/
private static void copyDir(File src, File dest) throws IOException {
dest.mkdirs();
//0.进入数据源
File[] files = src.listFiles();
//1.遍历数组
for (File file : files) {
if (file.isFile()){
//2.判断-文件-copy
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 {
//3.判断-文件夹-递归
copyDir(file,new File(dest,file.getName()));
}
}
}
练习2:(文件加密)
为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的的时候再对其进行解密处理。
加密原理:
对原始文件中的每一个字节数据进行更改,然后将更改以后得数据存储到新的文件中
解密原理:
读取加密之后的文件,按照加密的规则反向操作,变成原始文件。
加密:
public static void main(String[] args) throws IOException {
/*
* ^ : 异或
两边相同:false
两边不同:true
0:false
1:true
100:1100100
10: 1010
1100100
^ 0001010
__________
1101110
^ 0001010
__________
1100100
*/
//0.创建对象关联原始文件
FileInputStream fis = new FileInputStream("day28_code\\src\\MyTest\\a.jpg");
//1.创建对象关联加密文件
FileOutputStream fos = new FileOutputStream("day28_code\\src\\MyTest\\ency.jpg");
//2.加密处理
int len;
while ((len = fis.read()) != -1){
fos.write(len ^ 2);// 任意一个数字
}
//3.关流
fos.close();
fis.close();
}
解密:
public static void main(String[] args) throws IOException {
//0.创建对象关联原始文件
FileInputStream fis = new FileInputStream("day28_code\\src\\MyTest\\ency.jpg");
//1.创建对象关联加密文件
FileOutputStream fos = new FileOutputStream("day28_code\\src\\MyTest\\redu.jpg");
//2.解密处理
int len;
while ((len = fis.read()) != -1){
fos.write(len ^ 2);
}
//3.关流
fos.close();
fis.close();
}
练习3:(修改文件中的数据)
文本文件中有以下的数据:
2-1-9-4-7-8
将文件中的数据进行排序,变成一下的数据:
1-2-4-7-8-9
解法1:
public static void main(String[] args) throws IOException {
/*文本文件中有以下的数据:
2-1-9-4-7-8
将文件中的数据进行排序,变成一下的数据:
1-2-4-7-8-9
*/
//0.读取数据
FileReader fr = new FileReader("day28_code\\src\\MyTest\\Test4.txt");
StringBuilder sb = new StringBuilder();
int ch;
while ((ch = fr.read()) != -1) {
sb.append((char) ch);
}
fr.close();
//1.排序
String str = sb.toString();
String[] arrStr = str.split("-");
ArrayList<Integer> list = new ArrayList<>();
for (String s : arrStr) {
int num = Integer.parseInt(s);
list.add(num);
}
Collections.sort(list);
//2.写入文件
FileWriter fw = new FileWriter("day28_code\\src\\MyTest\\Test4.txt");
for (int i = 0; i < list.size(); i++) {
if (i == list.size() - 1) {
fw.write(list.get(i) + "");
} else {
fw.write(list.get(i) + "-");
}
}
fw.close();
}
解法2:
public static void main(String[] args) throws IOException {
/*文本文件中有以下的数据:
2-1-9-4-7-8
将文件中的数据进行排序,变成一下的数据:
1-2-4-7-8-9
*/
//0.读取数据
FileReader fr = new FileReader("day28_code\\src\\MyTest\\Test4.txt");
StringBuilder sb = new StringBuilder();
int ch;
while ((ch = fr.read()) != -1) {
sb.append((char) ch);
}
fr.close();
//1.排序
Integer[] arr = Arrays.stream(sb.toString()
.split("-"))
.map(Integer::parseInt)
.sorted()
.toArray(Integer[]::new);
//2.写入文件
FileWriter fw = new FileWriter("day28_code\\src\\MyTest\\Test4.txt");
String s = Arrays.toString(arr).replace(", ", "-");
String result = s.substring(1, s.length() - 1);
System.out.println(result);
fw.write(result);
fw.close();
}
三、高级流
3.1 缓冲流
3.1.1 字节缓冲流
public static void main(String[] args) throws IOException {
//0.创建缓冲流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day29_code\\src\\a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day29_code/src/copy.txt"));
//1.循环读取数据并写到文件中
int b;
while ((b = bis.read()) != -1){
bos.write(b);
}
bos.close();
bis.close();
}
public static void main(String[] args) throws IOException {
//0.创建缓冲流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day29_code/src/a.txt"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day29_code/src/copy2.txt"));
//1.循环读取数据并写到文件中
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
}
bos.close();
bis.close();
}
3.1.2 字符缓冲流
readLine()方法细节:
- readLine方法在读取的时候,依次读一整行,遇到回车换行结束
- 但是他不会把回车换行读到内存当中
public static void main(String[] args) throws IOException {
//0.创建对象
BufferedReader br = new BufferedReader(new FileReader("day29_code/src/a.txt"));
//1.读取数据
/*String line1 = br.readLine();
System.out.println(line1);*/
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
//2.关流
br.close();
}
public static void main(String[] args) throws IOException {
//0.创建对象
BufferedWriter bw = new BufferedWriter(new FileWriter("day29_code/src/b.txt",true));
//1.写入数据
bw.write("你嘴角上扬的样子,百度是搜不到的");
bw.newLine();
bw.write("我以后结婚,你一定要来哟!");
bw.newLine();
bw.write("我以后结婚,你一定要来哟!");
//2.关流
bw.close();
}
3.2 综合练习
练习1(拷贝文件)
四种方式拷贝文件,并统计各自用时
public static void main(String[] args) throws IOException {
/*四种方式拷贝文件,并统计各自用时*/
long start = System.currentTimeMillis();
method1(); // 共耗时:6.493 秒
// method2(); // 共耗时:0.008 秒
// method3(); // 共耗时:0.024 秒
// method4(); // 共耗时:0.006 秒
long end = System.currentTimeMillis();
System.out.println("共耗时:" + (end - start) / 1000.0 + " 秒");
}
private static void method4() throws IOException {
//字节缓冲流:一次读写一个字节数组
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\下载\\123.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day29_code/src/Test/copy.mp4"));
byte[] bytes = new byte[8192];
int len;
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
bos.close();
bis.close();
}
//字节缓冲流:一次读写一个字节
private static void method3() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\下载\\123.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day29_code/src/Test/copy.mp4"));
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
bos.close();
bis.close();
}
//字节流的基本流:一次读写一个字节数组
private static void method2() throws IOException {
FileInputStream fis = new FileInputStream("E:\\下载\\123.mp4");
FileOutputStream fos = new FileOutputStream("day29_code/src/Test/copy.mp4");
byte[] bytes = new byte[8192];
int len;
while ((len = fis.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
fos.close();
fis.close();
}
//字节流的基本流 一次读写一个字节4,588,568,576 字节
private static void method1() throws IOException {
FileInputStream fis = new FileInputStream("E:\\下载\\123.mp4");
FileOutputStream fos = new FileOutputStream("day29_code/src/Test/copy.mp4");
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
fos.close();
fis.close();
}
练习2(修改文本顺序)
需求:把《出师表》的文章顺序进行恢复到一个新文件中。
public static void main(String[] args) throws IOException {
/*需求:把《出师表》的文章顺序进行恢复到一个新文件中。*/
//0.创建对象
BufferedReader br = new BufferedReader(new FileReader("day29_code/src/Test/csb.txt"));
//1.读取数据
String b;
TreeSet<String> t = new TreeSet<>();
while ((b = br.readLine()) != null) {
t.add(b);
}
br.close();
//2.恢复数据
String[] arr = t.stream().sorted(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int first = Integer.parseInt(String.valueOf(o1.charAt(0)));
int second = Integer.parseInt(String.valueOf(o2.charAt(0)));
return first - second;
}
}).toArray(String[]::new);
//3.写出数据
BufferedWriter bw = new BufferedWriter(new FileWriter("day29_code/src/Test/newcsb.txt"));
for (String s : arr) {
System.out.println(s);
bw.write(s);
bw.newLine();
}
//4.关流
bw.close();
}
练习3(软件运行次数)
实现一个验证程序运行次数的小程序,要求如下:
1. 当程序运行超过3次时给出提示:本软件只能免费使用3次,欢迎您注册会员后继续使用~
2. 程序运行演示如下:
第一次运行控制台输出:欢迎使用本软件,第1次使用免费~
第二次运行控制台输出:欢迎使用本软件,第2次使用免费~
第三次运行控制台输出:欢迎使用本软件,第3次使用免费~
第四次及之后运行控制台输出:本软件只能免费使用3次,欢迎您注册会员后继续使用~
public static void main(String[] args) throws IOException {
/*实现一个验证程序运行次数的小程序,要求如下:
1. 当程序运行超过3次时给出提示:本软件只能免费使用3次,欢迎您注册会员后继续使用~
2. 程序运行演示如下:
第一次运行控制台输出:欢迎使用本软件,第1次使用免费~
第二次运行控制台输出:欢迎使用本软件,第2次使用免费~
第三次运行控制台输出:欢迎使用本软件,第3次使用免费~
第四次及之后运行控制台输出:本软件只能免费使用3次,欢迎您注册会员后继续使用~*/
//0.把文件中的数字读到内存中
BufferedReader br = new BufferedReader(new FileReader("day29_code/src/Test/count.txt"));
String line = br.readLine();
int count = Integer.parseInt(line);
br.close();
//运行一次+1
count++;
//判断
if (count <= 3) {
System.out.println("欢迎使用本软件,第" + count + "次使用免费~");
}else {
System.out.println("本软件只能免费使用3次,欢迎您注册会员后继续使用~");
}
//把自增的count写入到文件中
BufferedWriter bw = new BufferedWriter(new FileWriter("day29_code/src/Test/count.txt"));
bw.write(count+"");
bw.close();
}
IO流的使用原则:随用随创建、什么时候不用什么时候关闭
3.3 转换流
转换流是字符流和字节流之间的桥梁
转换文件编码
需求1:手动创建一个GBK的文件,把文件中的中文读取到内存中,不能出现乱码
需求2:把一段中文按照GBK的方式写到本地文件
需求3:将本地文件中的GBK文件,转成UTF-8
需求1:
public static void main(String[] args) throws IOException {
/*//0.创建对象并指定字符编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("day29_code\\src\\ConvertStream\\gbkfile.txt"),"GBK");
//1.读取数据
int ch;
while ((ch = isr.read()) != -1) {
System.out.print((char) ch);
}
isr.close();*/
//以上这种方式已经被淘汰了
//替代方案
FileReader fr = new FileReader("day29_code\\\\src\\\\ConvertStream\\\\gbkfile.txt", Charset.forName("GBK"));
//1.读取数据
int ch;
while ((ch = fr.read()) != -1) {
System.out.print((char) ch);
}
fr.close();
}
需求2:
public static void main(String[] args) throws IOException {
/*需求2:把一段中文按照GBK的方式写到本地文件*/
/*//0.创建转换流对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day29_code\\src\\ConvertStream\\a.txt"), "GBK");
//1.写出数据
osw.write("你好你好");
//2.释放资源
osw.close();*/
//以上方式淘汰
//替代方案
FileWriter fw = new FileWriter("day29_code\\src\\ConvertStream\\a.txt", Charset.forName("GBK"), true);
fw.write("\t\n我爱你");
fw.close();
}
需求3:将本地文件中的GBK文件,转成UTF-8
public static void main(String[] args) throws IOException {
/*需求3:将本地文件中的GBK文件,转成UTF-8*/
/*InputStreamReader isr = new InputStreamReader(new FileInputStream("day29_code\\src\\ConvertStream\\a.txt"), "GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("day29_code\\src\\ConvertStream\\b.txt"),"UTF-8");
int ch;
while ((ch = isr.read())!=-1){
osw.write(ch);
}
osw.close();
isr.close();*/
//替代方案
FileReader fr = new FileReader("day29_code\\src\\ConvertStream\\a.txt", Charset.forName("GBK"));
FileWriter fw = new FileWriter("day29_code\\src\\ConvertStream\\c.txt", Charset.forName("UTF-8"));
int b;
while ((b = fr.read()) != -1) {
fw.write(b);
}
fw.close();
fr.close();
}
利用字节流读取文件中的数据,每次读一整行,而且不能出现乱码
1. 字节流在读取中文的时候,是会出现乱码的,但是字符流可以搞定
2. 字节流里面是没有读一整行的方法的,只有字符缓冲流才能搞定
public static void main(String[] args) throws IOException {
/*利用字节流读取文件中的数据,每次读一整行,而且不能出现乱码
1. 字节流在读取中文的时候,是会出现乱码的,但是字符流可以搞定
2. 字节流里面是没有读一整行的方法的,只有字符缓冲流才能搞定*/
/*FileInputStream fis = new FileInputStream("day29_code\\src\\ConvertStream\\newcsb.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("day29_code\\src\\ConvertStream\\newcsb.txt")));
String len;
while ((len=br.readLine())!=null){
System.out.println(len);
}
br.close();
}
3.4 序列化流
package ObjectStream;
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
public static void main(String[] args) throws IOException {
/*把一个对象写到本地文件中*/
//0.创建学生对象
Student s1 = new Student("zhangsan", 23);
//1.创建序列化流的对象/对象操作输出流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day29_code\\src\\ObjectStream\\Student.txt"));
//2.写出数据
oos.writeObject(s1);
//3.释放资源
oos.close();
}
3.5 反序列化流
public static void main(String[] args) throws IOException, ClassNotFoundException {
//0.创建反序列化流的对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day29_code\\src\\ObjectStream\\Student.txt"));
//1.读取数据
Object o = ois.readObject();
System.out.println(o);
//2.释放资源
ois.close();
}
package ObjectStream;
import java.io.Serializable;
public class Student implements Serializable {
//第一种方法:手动添加
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String address;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
第二种方法:
之后应用
鼠标悬停在Student上可以看到
如果鼠标悬停没有显示,那么是版本不同换了位置,可以在File>Settings>Editor>Inspections>JVM languages下找到并勾选应用
之后ALT+Enter创建好就可以了。
public class Student implements Serializable {
@Serial
private static final long serialVersionUID = 2294754669754402810L;
private String name;
private int age;
private String address;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
练习:用对象流读写多个对象
需求:将多个自定义对象序列化到文件中,但是由于对象的个数不确定,反序列化流该如何读取呢?
package Test;
import java.io.Serial;
import java.io.Serializable;
public class Student implements Serializable {
@Serial
private static final long serialVersionUID = 8986009981186061115L;
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;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return address
*/
public String getAddress() {
return address;
}
/**
* 设置
* @param address
*/
public void setAddress(String address) {
this.address = address;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + ", address = " + address + "}";
}
}
public static void main(String[] args) throws IOException {
/*需求:将多个自定义对象序列化到文件中,但是由于对象的个数不确定,反序列化流该如何读取呢?*/
//0.创建学生对象
Student s1 = new Student("zhangsan", 23, "云南");
Student s2 = new Student("lisi", 24, "北京");
Student s3 = new Student("wangwu", 25, "四川");
ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
//1.创建序列化流对象
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day29_code/src/Test/Student.txt"));
//2.写入数据
oos.writeObject(list);
//3.释放资源
oos.close();
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
//0.创建反序列化流对象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day29_code/src/Test/Student.txt"));
//1.读取数据
ArrayList<Student> list = (ArrayList<Student>) ois.readObject();
for (Student s : list) {
System.out.println(s);
}
//2.释放资源
ois.close();
}
3.6 打印流
public static void main(String[] args) throws FileNotFoundException {
//0.创建字节打印流的对象
PrintStream ps = new PrintStream(new FileOutputStream("day29_code/src/PrintStream/a.txt"));
//1.写入数据
ps.println(97);
ps.print(true);
ps.printf("%s 爱上了 %s", "阿珍", "阿强");
//2.释放资源
ps.close();
}
public static void main(String[] args) throws IOException {
//0.创建字符打印流对象
PrintWriter pw = new PrintWriter(new FileWriter("day29_code/src/PrintStream/a.txt"),true);
//1.写出数据
pw.println("今天你终于叫我的名字了,虽然交错了,但没关系~");
pw.print("你好你好");
pw.printf("%s 爱上了 %s", "阿珍", "阿强");
//2.释放资源
pw.close();
}
3.7 解压缩流 / 压缩流
3.7.1 解压缩流
public static void main(String[] args) throws IOException {
//0.创建一个对象表示需要解压的文件
File src = new File("day29_code\\src\\zipStream\\aaa.zip");
//1.创建一个对象表示解压文件的存放目录
File dest = new File("day29_code\\src\\zipStream\\");
unZip(src, dest);
}
//定义一个方法用来解压文件
private static void unZip(File src, File dest) throws IOException {
//0.创建一个解压缩流用来读取压缩包中的数据
ZipInputStream zis = new ZipInputStream(new FileInputStream(src));
//1.读取数据
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
System.out.println(entry);
if (entry.isDirectory()) {
//文件夹
File file = new File(dest, entry.toString());
file.mkdirs();
} else {
//文件
FileOutputStream fos = new FileOutputStream(new File(dest, entry.toString()));
int b;
while ((b = zis.read()) != -1) {
fos.write(b);
}
fos.close();
zis.closeEntry();
}
}
zis.close();
}
3.7.2 压缩流
单个文件:
public static void main(String[] args) throws IOException {
//0.创建一个对象表示需要压缩的文件
File src = new File("day29_code\\src\\a.txt");
//1.创建一个对象表示压缩文件的存放目录
File dest = new File("day29_code\\src\\");
toZip(src, dest);
}
private static void toZip(File src, File dest) throws IOException {
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File(dest, "a.zip")));
//创建ZipEntry对象
ZipEntry entry = new ZipEntry("a.txt");
zos.putNextEntry(entry);
//拷贝文件中的数据
FileInputStream fis = new FileInputStream(src);
int b;
while ((b = fis.read()) != -1) {
zos.write(b);
}
fis.close();
zos.close();
}
压缩文件夹
public static void main(String[] args) throws IOException {
//0.创建File对象表示要压缩的文件夹
File src = new File("day29_code/src/zipStream/bbb");
//1.创建File对象表示压缩包放在哪里
File parentFile = src.getParentFile();
//2.创建对象表示压缩文件的路径
File dest = new File(parentFile, src.getName() + ".zip");
//3.创建压缩流关联压缩包
ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(dest));
//4.获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包中
toZip(src, zos, src.getName());
//5.释放资源
zos.close();
}
/*作用:获取src里面的每一个文件,变成ZipEntry对象,放入到压缩包当中
* 参数一:数据源
* 参数二:压缩流
* 参数三:压缩包内部的路径*/
private static void toZip(File src, ZipOutputStream zos, String name) throws IOException {
//0.进入src文件夹
File[] files = src.listFiles();
//1.遍历数组
for (File file : files) {
if (file.isFile()) {
//判断文件 将其变成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 {
//判断文件夹 递归
toZip(file, zos, name + "\\" + file.getName());
}
}
}
3.8 Commons-io
1,IOUtils(数据相关)
拷贝方法:
copy方法有多个重载方法,满足不同的输入输出流
IOUtils.copy(InputStream input, OutputStream output)
IOUtils.copy(InputStream input, OutputStream output, int bufferSize)//可指定缓冲区大小
IOUtils.copy(InputStream input, Writer output, String inputEncoding)//可指定输入流的编码表
IOUtils.copy(Reader input, Writer output)
IOUtils.copy(Reader input, OutputStream output, String outputEncoding)//可指定输出流的编码表
拷贝大文件的方法:
// 这个方法适合拷贝较大的数据流,比如2G以上
IOUtils.copyLarge(Reader input, Writer output) // 默认会用1024*4的buffer来读取
IOUtils.copyLarge(Reader input, Writer output, char[] buffer)//可指定缓冲区大小
将输入流转换成字符串
IOUtils.toString(Reader input)
IOUtils.toString(byte[] input, String encoding)
IOUtils.toString(InputStream input, Charset encoding)
IOUtils.toString(InputStream input, String encoding)
IOUtils.toString(URI uri, String encoding)
IOUtils.toString(URL url, String encoding)
将输入流转换成字符数组
IOUtils.toByteArray(InputStream input)
IOUtils.toByteArray(InputStream input, int size)
IOUtils.toByteArray(URI uri)
IOUtils.toByteArray(URL url)
IOUtils.toByteArray(URLConnection urlConn)
IOUtils.toByteArray(Reader input, String encoding)
字符串读写
IOUtils.readLines(Reader input)
IOUtils.readLines(InputStream input, Charset encoding)
IOUtils.readLines(InputStream input, String encoding)
IOUtils.writeLines(Collection<?> lines, String lineEnding, Writer writer)
IOUtils.writeLines(Collection<?> lines, String lineEnding, OutputStream output, Charset encoding)
IOUtils.writeLines(Collection<?> lines, String lineEnding, OutputStream output, String encoding)
从一个流中读取内容
IOUtils.read(InputStream input, byte[] buffer)
IOUtils.read(InputStream input, byte[] buffer, int offset, int length) IOUtils.read(Reader input, char[] buffer)
IOUtils.read(Reader input, char[] buffer, int offset, int length)
把数据写入到输出流中
IOUtils.write(byte[] data, OutputStream output)
IOUtils.write(byte[] data, Writer output, Charset encoding)
IOUtils.write(byte[] data, Writer output, String encoding)
IOUtils.write(char[] data, Writer output)
IOUtils.write(char[] data, OutputStream output, Charset encoding)
IOUtils.write(char[] data, OutputStream output, String encoding)
IOUtils.write(String data, Writer output)
IOUtils.write(CharSequence data, Writer output)
从一个流中读取内容,如果读取的长度不够,就会抛出异常
IOUtils.readFully(InputStream input, int length)
IOUtils.readFully(InputStream input, byte[] buffer)
IOUtils.readFully(InputStream input, byte[] buffer, int offset, int length) IOUtils.readFully(Reader input, char[] buffer)
IOUtils.readFully(Reader input, char[] buffer, int offset, int length)
比较
IOUtils.contentEquals(InputStream input1, InputStream input2) // 比较两个流是否相等
IOUtils.contentEquals(Reader input1, Reader input2)
IOUtils.contentEqualsIgnoreEOL(Reader input1, Reader input2) // 比较两个流,忽略换行符
其他方法
IOUtils.skip(InputStream input, long toSkip) // 跳过指定长度的流
IOUtils.skip(Reader input, long toSkip)
IOUtils.skipFully(InputStream input, long toSkip) // 如果忽略的长度大于现有的长度,就会抛出异常
IOUtils.skipFully(Reader input, long toSkip)
2,FileUtils(文件/文件夹相关)
复制文件夹
FileUtils.copyDirectory(File srcDir, File destDir) // 复制文件夹(文件夹里面的文件内容也会复制)
FileUtils.copyDirectory(File srcDir, File destDir, FileFilter filter) // 复制文件夹,带有文件过滤功能
FileUtils.copyDirectoryToDirectory(File srcDir, File destDir) // 以子目录的形式将文件夹复制到到另一个文件夹下
复制文件
FileUtils.copyFile(File srcFile, File destFile) // 复制文件
FileUtils.copyFile(File input, OutputStream output) // 复制文件到输出流
FileUtils.copyFileToDirectory(File srcFile, File destDir) // 复制文件到一个指定的目录
FileUtils.copyInputStreamToFile(InputStream source, File destination) // 把输入流里面的内容复制到指定文件
FileUtils.copyURLToFile(URL source, File destination) // 把URL 里面内容复制到文件(可以下载文件)
FileUtils.copyURLToFile(URL source, File destination, int connectionTimeout, int readTimeout)
把字符串写入文件
FileUtils.writeStringToFile(File file, String data, String encoding)
FileUtils.writeStringToFile(File file, String data, String encoding, boolean append)
把字节数组写入文件
FileUtils.writeByteArrayToFile(File file, byte[] data)
FileUtils.writeByteArrayToFile(File file, byte[] data, boolean append) FileUtils.writeByteArrayToFile(File file, byte[] data, int off, int len) FileUtils.writeByteArrayToFile(File file, byte[] data, int off, int len, boolean append)
把集合里面的内容写入文件
// encoding:文件编码,lineEnding:每行以什么结尾
FileUtils.writeLines(File file, Collection<?> lines)
FileUtils.writeLines(File file, Collection<?> lines, boolean append)
FileUtils.writeLines(File file, Collection<?> lines, String lineEnding)
FileUtils.writeLines(File file, Collection<?> lines, String lineEnding, boolean append)
FileUtils.writeLines(File file, String encoding, Collection<?> lines)
FileUtils.writeLines(File file, String encoding, Collection<?> lines, boolean append)
FileUtils.writeLines(File file, String encoding, Collection<?> lines, String lineEnding)
FileUtils.writeLines(File file, String encoding, Collection<?> lines, String lineEnding, boolean append)
往文件里面写内容
FileUtils.write(File file, CharSequence data, Charset encoding)
FileUtils.write(File file, CharSequence data, Charset encoding, boolean append)
FileUtils.write(File file, CharSequence data, String encoding)
FileUtils.write(File file, CharSequence data, String encoding, boolean append)
文件移动
FileUtils.moveDirectory(File srcDir, File destDir) // 文件夹在内的所有文件都将移动FileUtils.moveDirectoryToDirectory(File src, File destDir, boolean createDestDir) // 以子文件夹的形式移动到另外一个文件下
FileUtils.moveFile(File srcFile, File destFile) // 移动文件
FileUtils.moveFileToDirectory(File srcFile, File destDir, boolean createDestDir) // 以子文件的形式移动到另外一个文件夹下
FileUtils.moveToDirectory(File src, File destDir, boolean createDestDir) // 移动文件或者目录到指定的文件夹内
清空和删除文件夹
FileUtils.deleteDirectory(File directory) // 删除文件夹,包括文件夹和文件夹里面所有的文件
FileUtils.cleanDirectory(File directory) // 清空文件夹里面的所有的内容
FileUtils.forceDelete(File file) // 删除,会抛出异常
FileUtils.deleteQuietly(File file) // 删除,不会抛出异常
创建文件夹
FileUtils.forceMkdir(File directory) // 创建文件夹(可创建多级)
FileUtils.forceMkdirParent(File file) // 创建文件的父级目录
获取文件输入/输出流
FileUtils.openInputStream(File file)
FileUtils.openOutputStream(File file)
读取文件
FileUtils.readFileToByteArray(File file) // 把文件读取到字节数组
FileUtils.readFileToString(File file, Charset encoding) // 把文件读取成字符串
FileUtils.readFileToString(File file, String encoding)
FileUtils.readLines(File file, Charset encoding) // 把文件读取成字符串集合
FileUtils.readLines(File file, String encoding)
测试两个文件的修改时间
FileUtils.isFileNewer(File file, Date date)
FileUtils.isFileNewer(File file, File reference)
FileUtils.isFileNewer(File file, long timeMillis)
FileUtils.isFileOlder(File file, Date date)
FileUtils.isFileOlder(File file, File reference)
FileUtils.isFileOlder(File file, long timeMillis)
文件/文件夹的迭代
FileUtils.iterateFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter)
FileUtils.iterateFiles(File directory, String[] extensions, boolean recursive)
FileUtils.iterateFilesAndDirs(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter)
FileUtils.lineIterator(File file)
FileUtils.lineIterator(File file, String encoding)
FileUtils.listFiles(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter)
FileUtils.listFiles(File directory, String[] extensions, boolean recursive)
FileUtils.listFilesAndDirs(File directory, IOFileFilter fileFilter, IOFileFilter dirFilter)
其他
FileUtils.isSymlink(File file) // 判断是否是符号链接
FileUtils.directoryContains(File directory, File child) // 判断文件夹内是否包含某个文件或者文件夹
FileUtils.sizeOf(File file) // 获取文件或者文件夹的大小
FileUtils.getTempDirectory()// 获取临时目录文件
FileUtils.getTempDirectoryPath()// 获取临时目录路径
FileUtils.getUserDirectory()// 获取用户目录文件
FileUtils.getUserDirectoryPath()// 获取用户目录路径
FileUtils.touch(File file) // 创建文件
FileUtils.contentEquals(File file1, File file2) // 比较两个文件内容是否相同
FilenameUtils(文件名/后缀名相关)
FilenameUtils.concat(String basePath, String fullFilenameToAdd) // 合并目录和文件名为文件全路径
FilenameUtils.getBaseName(String filename) // 去除目录和后缀后的文件名
FilenameUtils.getExtension(String filename) // 获取文件的后缀
FilenameUtils.getFullPath(String filename) // 获取文件的目录
FilenameUtils.getName(String filename) // 获取文件名
FilenameUtils.getPath(String filename) // 去除盘符后的路径
FilenameUtils.getPrefix(String filename) // 盘符
FilenameUtils.indexOfExtension(String filename) // 获取最后一个.的位置
FilenameUtils.indexOfLastSeparator(String filename) // 获取最后一个/的位置
FilenameUtils.normalize(String filename) // 获取当前系统格式化路径
FilenameUtils.removeExtension(String filename) // 移除文件的扩展名
FilenameUtils.separatorsToSystem(String path) // 转换分隔符为当前系统分隔符
FilenameUtils.separatorsToUnix(String path) // 转换分隔符为linux系统分隔符
FilenameUtils.separatorsToWindows(String path) // 转换分隔符为windows系统分隔符
FilenameUtils.equals(String filename1, String filename2) // 判断文件路径是否相同,非格式化
FilenameUtils.equalsNormalized(String filename1, String filename2) // 判断文件路径是否相同,格式化
FilenameUtils.directoryContains(String canonicalParent, String canonicalChild) // 判断目录下是否包含指定文件或目录
FilenameUtils.isExtension(String filename, String extension) // 判断文件扩展名是否包含在指定集合(数组、字符串)中
FilenameUtils.wildcardMatch(String filename, String wildcardMatcher) // 判断文件扩展名是否和指定规则匹配
Hutool工具包
官网:
https://hutool.cn/
API文档:
https://apidoc.gitee.com/dromara/hutool/
中文使用文档:
https://hutool.cn/docs/#/