【JAVA入门】Day40 - 字符流
文章目录
- [【JAVA入门】Day40 - 字符流](#【JAVA入门】Day40 - 字符流)
-
- [一、Reader ------ 字符输入流](#一、Reader —— 字符输入流)
- [二、Writer ------ 字符输出流](#二、Writer —— 字符输出流)
- 三、字节流和字符流的使用场景
字符流的底层就是字符流+字符集,它能实现在读取时,碰到英文字母,还按 1 个字节读取,碰到汉字时,则按多个字节读取(UTF-8 是 3 个字节,GBK 是 2 个字节)。因此,字符流用于纯文本场景的数据输入和输出。
一、Reader ------ 字符输入流
Reader 是字符输入流的抽象总类,它不能直接创建对象。但是有 FileReader 继承 Reader,它可以实现对本地文件的字符输入。
FileReader 的使用步骤如下:
代码实现。
① read() 空参读取:
java
package IOCharStream;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo1 {
public static void main(String[] args) throws IOException {
/*
字符输入流的使用
*/
//1.创建对象
FileReader fr = new FileReader("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\hhh.txt");
//2.读取数据 read() 空参
int ch;
while((ch = fr.read()) != -1){
System.out.print((char)ch);
}
//read() 细节:
//1.默认一个字节一个字节读取,但是遇到中文会一次读 3 个字节(默认UTF-8)
//2.该方法读取的字符会将二进制转成十进制,这个十进制也表示在字符集上的数字
//3.如果想看中文汉字,直接将这些十进制数据强转即可
//3.释放资源
fr.close();
}
}
② 带参 read() 方法详解:
java
package IOCharStream;
import java.io.FileReader;
import java.io.IOException;
public class CharStreamDemo2 {
public static void main(String[] args) throws IOException {
/*
public int read(char[] buffer) //一次读取多个数据,参数为char类型数组,返回值为读取到的字符个数
*/
//1.创建对象
FileReader fr = new FileReader("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\hhh.txt");
//2.读取数据
char[] chars = new char[2]; //一次读两个字符
int len;
//read(chars):读取数据,解码,强制类型转换,三合一,将强转之后的字符放入数组中
//带参read = 空参read + 强转
while((len = fr.read(chars)) != -1){
//把数组中的数据变成字符串再打印
System.out.print(new String(chars, 0 , len)); //转字符串细节:从0索引到len索引转
}
//3.释放资源
fr.close();
}
}
二、Writer ------ 字符输出流
Writer 是字符输出流的抽象总类,它不能直接创建对象。但有 FileWriter 继承自它,可以实现对本地文件数据的输出。
FileWriter 的使用方法如下:
① 利用构造方法生成对象。
细节1:参数是字符串表示的路径或者 File 对象表示的路径都可以。
细节2:如果文件不存在,会自动创建一个新的文件,但要保证父级路径是存在的。
细节3:如果文件已存在,默认覆写文件,如果不想清空可以打开续写开关。
② 调用成员方法写出。
细节:如果 write 方法的参数是一个整数,实际上写到本地文件中的是这个整数在字符集上对应的 char 字符。
③ 释放资源。
方法用例:
java
package IOCharStream;
import java.io.FileWriter;
import java.io.IOException;
public class CharStreamDemo3 {
public static void main(String[] args) throws IOException {
/*
文件写出
*/
FileWriter fw = new FileWriter("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\heyhey.txt");
//1.一次写一个字符
fw.write(25105); //根据字符集编码方式(UTF-8)进行编码,把编码之后的数据写到文件中去
fw.close();
//2.一次写一个字符串
FileWriter fw2 = new FileWriter("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\heyhey.txt");
fw2.write("嘿嘿嘿");
fw2.close();
//3.用字符数组写出
char[] chars = {'我','喜','欢','你'};
FileWriter fw3 = new FileWriter("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\heyhey.txt",true);
fw3.write(chars);
fw3.close();
//4.写出字符串的一部分
FileWriter fw4 = new FileWriter("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\heyhey.txt");
fw4.write("嘿嘿嘿",0,2); //写出0索引起始的2个字符
fw4.close();
//5.写出字符数组的一部分
FileWriter fw5 = new FileWriter("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\heyhey.txt",true);
fw5.write(chars,1,3); //写出1索引起始的3个字符
fw5.close();
}
}
三、字节流和字符流的使用场景
字节流可以拷贝任意类型的文件,而字符流可以读取纯文本文件 中的数据,也可以往纯文本文件 写出数据。
【练习1】递归拷贝文件夹(拷贝文件都用字节流)。
java
package IOCharStream;
import java.io.*;
public class CharStreamTest1 {
public static void main(String[] args) throws IOException {
/*
拷贝一个文件夹 D:\IdeaProjects\HelloWord\src\IOCharStream\MyFiles
to
D:\IdeaProjects\HelloWord\src\IOCharStream\CopiedFiles
*/
//1.创建对象表示数据源
File src = new File("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\MyFiles");
//2.创建对象表示目的地
File dest = new File("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\CopiedFiles");
//3.调用方法开始拷贝
copydir(src,dest);
}
/*
作用:拷贝文件夹
*/
private static void copydir(File src, File dest) throws IOException {
//先创建dest文件夹,防止它不存在
dest.mkdirs();
//递归
//1.进入数据源
File[] files = src.listFiles();
//2.遍历数组
for (File file : files) {
//3.判断是文件,直接拷贝,判断是文件夹,递归
if(file.isFile()){
//细节:拷贝时一定是从文件开始,到文件结束,因此目的地路径要写成文件
// 新建一个对象,父级路径是目的地文件夹,子级路径(文件名)可以用getName方法获取
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new File(dest, file.getName()));
byte[] bytes = new byte[1024 * 1024 * 5];
int len;
while((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
}else{
//如果是文件夹,递归
copydir(file,new File(dest, file.getName()));
}
}
}
}
【练习2】文件加密。
为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的时候再对其进行解密处理。
加密原理:
对原始文件中的每一个字节数据进行更改,然后将更改以后的数据存储到新的文件中。
解密原理:
读取加密之后的文件,按照加密的规则反向操作,变成原始文件。
java
package IOCharStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class CharStreamTest2 {
public static void main(String[] args) throws IOException {
/*
为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的时候再对其进行解密处理。
加密原理:
对原始文件中的每一个字节数据进行更改,然后将更改以后的数据存储到新的文件中。
解密原理:
读取加密之后的文件,按照加密的规则反向操作,变成原始文件。
^:异或
两边相同:false
两边不同:true
被加密的图片:D:\IdeaProjects\HelloWord\src\IOCharStream\舞动新春.png
*/
//1.创建对象关联原始文件
FileInputStream fis = new FileInputStream("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\舞动新春.png");
//2.创建加密后的文件对象
FileOutputStream fos = new FileOutputStream("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\ency.png");
//3.加密处理
int b;
while((b = fis.read()) != -1){
fos.write(b ^ 100); //通过异或加密
}
fos.close();
//解密时互换路径即可
}
}
【练习3】排序。修改文件中的数据,让他们排序:
2-1-9-4-7-8
to
1-2-4-7-8-9
【解法1】使用ArrayList和Collections排序。
java
package IOCharStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class CharStreamTest3 {
public static void main(String[] args) throws IOException {
/*
修改文件中的数据,让他们排序
2-1-9-4-7-8
to
1-2-4-7-8-9
*/
//1.读入源文件
FileReader fr = new FileReader("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\File.txt");
StringBuilder sb = new StringBuilder();
//2.将数据存入sb
int ch;
while((ch = fr.read()) != -1){
sb.append((char)ch);
}
//sb转字符串
String str = sb.toString();
//切割字符串
String[] arrStr = str.split("-");
//变成整数列表
ArrayList<Integer> arr = new ArrayList<>();
for (String s : arrStr) {
arr.add(Integer.parseInt(s));
}
//调用Collections工具类排序
Collections.sort(arr);
System.out.println(arr);
//转回字符且拼接-写出文件
FileWriter fw = new FileWriter("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\File.txt");
for(int i = 0; i < arr.size(); i++){
//是最后一个元素,不附 - ,不是最后一个元素,附上 -
if(i == arr.size() - 1){
//把每一位Integer数字转字符串原样写出
fw.write(arr.get(i) + "");
}else{
fw.write(arr.get(i) + "-");
}
}
fw.close();
}
}
【解法2】使用流处理。
java
package IOCharStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class CharStreamTest4 {
public static void main(String[] args) throws IOException {
/*
修改文件中的数据,让他们排序
2-1-9-4-7-8
to
1-2-4-7-8-9
*/
//1.读入源文件
FileReader fr = new FileReader("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\File.txt");
StringBuilder sb = new StringBuilder();
//2.将数据存入sb
int ch;
while((ch = fr.read()) != -1){
sb.append((char)ch);
}
fr.close();
//使用ArrayList的流处理
Integer[] arr = Arrays.stream(sb.toString()
.split("-"))
.map(Integer::parseInt)
.sorted()
.toArray(Integer[]::new);
//转回字符且拼接-写出文件
//把原字符串的分隔符修改为-
String str = Arrays.toString(arr).replaceAll(", ","-"); //[1, 2, 4, 7, 8, 9]
System.out.println(str); //[1-2-4-7-8-9]
//截取中间的数字
String result = str.substring(1, str.length() - 1);
//写出数据
FileWriter fw = new FileWriter("D:\\IdeaProjects\\HelloWord\\src\\IOCharStream\\File.txt");
fw.write(result);
fw.close();
}
}