Java|IO流之字符流
1. 字符流出现的原因
由于字节流操作中文不是特别方便,所以,java就提供了字符流。
字符流 = 字节流 + 编码表
常见编码表:
- ASCII
- Unicode
- GB2312
- UTF-8
2. String类中的编码和解码
编码: 就是把字符串转换成字节数组 String ===> byte[]
- public byte[] getBytes();
使用平台的默认字符集将此 String编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 - public byte[] getBytes(String charsetName)
使用指定的字符集将此 String 编码为 byte 序列,并将
String s="hahahaha";
byte[] bytes = s.getBytes();
System.out.println(bytes);
byte[] gbks = s.getBytes("GBK");
System.out.println(gbks);
解码: 把字节数组转换成字符串 bytes[] ===> String
- public String(byte[] bytes):
通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。 - public String(byte[] bytes, String charsetName)
通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String
String s1 = new String(bytes);
System.out.println(s1);
String s2 = new String(gbks, "GBK");
System.out.println(s2);
3. 字符转换流:InputStreamReader
InputStreamReader:
字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
构造方法:
- 1.InputStreamReader(InputStream in)
创建一个使用默认字符集的 InputStreamReader。 - 2.InputStreamReader(InputStream in, String charsetName)
创建使用指定字符集的 InputStreamReader。
InputStreamReader reader = new InputStreamReader(new FileInputStream("bb.txt"));
成员方法
- 1.public int read()
一次读取一个字符 - 2.public int read(char[] cbuf)
一次读取一个字符数组 如果没有读到 返回-1
char[] chs = new char[1024];
reader.read(chs);
System.out.println(String.valueOf(chs));
reader.close();
4. 字符转换流:OutputStreamWriter
OutputStreamWriter:
字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
构造方法:
-
1.OutputStreamWriter(OutputStream out)
创建使用默认字符编码的 OutputStreamWriter。 -
2.OutputStreamWriter(OutputStream out, String charsetName)
创建使用指定字符集的 OutputStreamWriter。
成员方法: -
1.public void write(int c)
写一个字符 -
2.public void write(char[] cbuf)
写一个字符数组 -
3.public void write(char[] cbuf,int off,int len)
写一个字符数组的 一部分 -
4.public void write(String str)
写一个字符串 -
5.public void write(String str,int off,int len)
写一个字符串的一部分
writer1.write("abc");
//字符流必须要刷新
writer1.flush();
writer1.write("\r\n");
writer1.flush();
writer1.write("222");
writer1.flush();
writer1.write("222");
writer1.flush();
//刷新并关闭
writer1.close();
writer2.close();
注意:
1.字符流必须要刷新;
2.close()实际完成了刷新并关闭流的功能
3.如果文件不大,close()就够用了;如果文件很大,有几百G,就需要flush().
5. 字符转换流的子类:FileReader和FileWriter
转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类。
转换流 | 便捷类 |
---|---|
OutputStreamWriter | FileWriter |
InputStreamReader | FileReader |
转换流与便捷类的唯一区别是:便捷类不能指定编码
示例:用便捷流复制文件
//用便捷流复制文件
FileReader reader = new FileReader("copydemo.java");
FileWriter writer = new FileWriter("copydemo(2).java");
char[] chars = new char[1024];
int len=0;
while ((len=reader.read(chars))!=-1){
writer.write(chars,0,len);
writer.flush();
}
reader.close();
writer.close();
6. 字符缓冲流:BufferedReader 和 BufferedReader
BufferedWriter
构造方法:
- public BufferedWriter(Writer w)
特殊的成员方法:
- BufferedWriter: public void newLine():
根据系统来决定换行符 具有系统兼容性的换行符
BufferedReader
构造方法:
- public BufferedReader(Reader e)
特殊的成员方法:
- BufferedReader: public String readLine():
一次读取一行数据 是以换行符为标记的 读到换行符就换行 没读到数据返回null;包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
示例:字符缓冲流的特殊功能复制文本文件(一行一行复制)
BufferedReader reader = new BufferedReader(new FileReader("copydemo.java"));
BufferedWriter writer = new BufferedWriter(new FileWriter("copydemo(3).java"));
String line=null;
while ((line=reader.readLine())!=null){
writer.write(line);
writer.newLine(); //换行符,具有平台兼容性
writer.flush();
}
reader.close();
writer.close();
7. 几个示例
7.1 把ArrayList集合中的字符串数据存储到文本文件
//1.把ArrayList集合中的字符串数据存储到文本文件
ArrayList<String> list = new ArrayList<>();
list.add("abc");
list.add("cde");
list.add("fff");
FileOutputStream out = new FileOutputStream("list.txt");
for (String s : list) {
out.write(s.getBytes());
out.write("\r\n".getBytes());
out.flush();
}
out.close();
7.2 把文本文件中的数据(每一行为一个字符串数据)存储到集合中
//2.把文本文件中的数据(每一行为一个字符串数据)存储到集合中
BufferedReader reader = new BufferedReader(new FileReader("copydemo.java"));
ArrayList<String> list = new ArrayList<>();
String line=null;
while ((line=reader.readLine())!=null){
list.add(line);
}
reader.close();
for (String s : list) {
System.out.println(s);
}
7.3 有一个文本文件,每一行是一个学生的名字,请写一个程序,每次允许随机获取一个学生名称
//3.有一个文本文件,每一行是一个学生的名字,请写一个程序,每次允许随机获取一个学生名称
ArrayList<String> list = new ArrayList<>();
BufferedReader reader = new BufferedReader(new FileReader("studentName.txt"));
String line=null;
while ((line=reader.readLine())!=null){
list.add(line);
}
reader.close();
Random random = new Random();
int i = random.nextInt(list.size());
System.out.println(list.get(i));
7.4 复制多级文件夹,如果有文件夹内有.png的文件,把后缀名改为.jpg
package exerciseDemo;
import java.io.*;
public class MyTest4 {
public static void main(String[] args) throws IOException {
//复制文件夹,如果有文件夹内有.png的文件,把后缀名改为.jpg
File fileSource = new File("multiDemo");
System.out.println(fileSource.exists());
File fileTarget = new File("multiDomoAndRename");
if(!fileTarget.exists()){
fileTarget.mkdir();
}
fileCopyAndRename(fileSource,fileTarget);
}
private static void fileCopyAndRename(File fileSource, File fileTarget) throws IOException {
//复制一个文件夹,并文件夹内有.png的文件,把后缀名改为.jpg
// FileInputStream in = new FileInputStream(fileSource);
// FileOutputStream out = new FileOutputStream(fileTarget);
File[] files = fileSource.listFiles();
for (File file : files) {
if(file.isFile()){
//如果是文件
if(file.getName().endsWith(".png")){
String newfileName = file.getName().replace(".png", ".jpg");
File filenew = new File(fileTarget, newfileName);
copyFunc(file,filenew);
}else{
File file1 = new File(fileTarget, file.getName());
copyFunc(file,file1);
}
}else if(file.isDirectory()){
//如果是文件夹,递归处理
//新建一个文件夹
File file1 = new File(fileTarget, file.getName());
file1.mkdir();
//复制
fileCopyAndRename(file,file1);
}
}
}
private static void copyFunc(File fileSource, File fileTarget) throws IOException {
//复制一个文件
FileInputStream in = new FileInputStream(fileSource);
FileOutputStream out = new FileOutputStream(fileTarget);
byte[] bytes = new byte[1024 * 8];
int len=0;
while ((len=in.read(bytes))!=-1){
out.write(bytes,0,len);
out.flush();
}
in.close();
out.close();
}
}
7.5 键盘录入3个学生信息(姓名, 语文成绩 数学成绩, 英语成绩, 按照总分从高到低存入文本文件
package exerciseDemo;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.Date;
import java.util.Scanner;
import java.util.TreeSet;
public class MyTest5 {
public static void main(String[] args) throws IOException {
// 键盘录入3个学生信息(姓名, 语文成绩(chineseScore),
// 数学成绩(mathScore), 英语成绩(englishScore)), 按照总分从高到低存入文本文件
// 方式0:每次写入,覆盖上次的内容
// 方式1.追加写入
// 方式2.每次写入一个新的文件,文件名包含时间信息
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//按照总分排大小
int num= s1.totalScore()-s2.totalScore();
//再比较姓名
int num2=num==0?s1.getName().compareTo(s2.getName()):num;
return num2;
}
});
for (int i = 1; i <= 3; i++) {
Student student = new Student();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入"+i+"个学生的姓名");
String name = scanner.nextLine();
student.setName(name);
System.out.println("请输入" + i + "个学生的语文成绩");
int yw = scanner.nextInt();
student.setChineseScore(yw);
System.out.println("请输入" + i + "个学生的数学成绩");
int xs= scanner.nextInt();
student.setMathScore(xs);
System.out.println("请输入" + i + "个学生的英语成绩");
int yy = scanner.nextInt();
student.setEnglishScore(yy);
//把学生添加到集合里面去
treeSet.add(student);
}
// 方式0:每次写入,覆盖上次的内容
// BufferedWriter writer = new BufferedWriter(new FileWriter("Student.txt"));
// 方式1.追加写入
//BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("Student.txt",true)));
// 方式2.每次写入一个新的文件文件名包含时间信息
long l = System.currentTimeMillis();
Date date = new Date(l);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_MM_dd_HH:mm:ss");
String format = simpleDateFormat.format(date);
String filename="Student_".concat(format);
BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
//收到写一样表头
writer.write("编号"+"\t"+"姓名"+"\t"+"语文"+"\t"+"数学"+"\t"+"外语"+"\t"+"总分");
writer.newLine();
writer.flush();
//遍历集合把学生的数据存到文本文件中
int index=1;
for (Student student : treeSet) {
writer.write(index+"\t"+student.getName()+"\t"+student.getChineseScore()+"\t"+student.getMathScore()+"\t"+student.getEnglishScore()+"\t"+student.totalScore());
writer.newLine();
writer.flush();
index++;
}
writer.close();
}
}