Java从入门到放弃21—字符流/String类中的编码和解码问题/转换流/高效的字符流
01 字符流概述
字符流:可以指定码表,方便操作不同语言。而字节流不可以指定码表
字符流:只能读写文本文件。字节流:可以读写任意数据类型的文件。
02 String类中的编码与解码
编码:把字符串转为字节数组
//byte[] getBytes()通过使用平台默认的charset编码到byte序列,并将结果存储到一个新的bte数组中。
//byte[] getBytes(Charset charset)通过使用给定的charset编码到byte序列,并将结果存储到一个新的byte数组中。
解码:把字节数组转为字符串
//String(byte[] bytes)通过使用平台默认字符集解码指定的byte数组,构造一个新的String
//String(byte[],Charset charset)通过使用给定的charset解码制定的byte数组,构造一个新的string
03 OutputStreamWriter
OutputStreamWriter 是字符流通向字节流的桥梁可使用指定的 charset 将要写入流中的字符编码成字节。它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。每次调用 write() 方法都会导致在给定字符(或字符集)上调用编码转换器。在写入底层输出流之前,得到的这些字节将在缓冲区中累积。
构造方法:
OutputStreamWriter(OutputStream out)
创建使用默认字符编码的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, Charset cs)
创建使用给定字符集的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, CharsetEncoder enc)
创建使用给定字符集编码器的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName)
创建使用指定字符集的 OutputStreamWriter。
常用方法:
public void write(int c) 写一个字符
public void write(char[] cbuf) 写一个字符数组
public void write(char[] cbuf,int off,int len) 写一个字符数组的 一部分
public void write(String str) 写一个字符串
public void write(String str,int off,int len) 写一个字符串的一部分
04 InputStreamReader
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
构造方法:
InputStreamReader(InputStream in)
创建一个使用默认字符集的 InputStreamReader。
InputStreamReader(InputStream in, Charset cs)
创建使用给定字符集的 InputStreamReader。
InputStreamReader(InputStream in, CharsetDecoder dec)
创建使用给定字符集解码器的 InputStreamReader。
InputStreamReader(InputStream in, String charsetName)
创建使用指定字符集的 InputStreamReader
常用方法:
public int read() 一次读取一个字符
public int read(char[] cbuf) 一次读取一个字符数组 如果没有读到 返回-1
05 高效的字符流
BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。可以指定缓冲区的大小,或者可使用默认的大小。
BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。可以指定缓冲区的大小,或者接受默认的大小。
构造方法:
BufferedWriter:public BufferedWriter(Writer w)
BufferedReader:public BufferedReader(Reader e)
特殊方法:
BufferedWriter: public void newLine():根据系统来决定换行符 具有系统兼容性的换行符
BufferedReader: public String readLine():一次读取一行数据 是以换行符为标记的 读到换行符就换行 没读到数据返回null 包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
06 字符缓冲流的特殊功能复制文本文件
public class Test {
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new FileReader("Test1.java"));
BufferedWriter bfw = new BufferedWriter(new FileWriter("Test2.java"));
String line = null;
while ((line = bfr.readLine()) != null) { //注意读取不到返回null
bfw.write(line);
bfw.newLine();
bfw.flush();
}
bfr.close();
bfw.close();
}
}
案例1:使用Java的IO流实现随机获取文本文件中的姓名
public class Test {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("username.txt"));
ArrayList<String> list = new ArrayList<>();
//把文本文件中的数据通过高效的字符流存储到集合中
while (true){
String line = bufferedReader.readLine();
if (line!=null){
list.add(line);
}else {
break;
}
}
bufferedReader.close();
Random random =new Random();
int nextInt = random.nextInt(list.size());
System.out.println(list.get(nextInt));
}
}
案例2:使用Java的IO流实现复制单级/多级文件夹
public class Test {
public static void main(String[] args) throws IOException {
//复制多级文件夹
//1.封装源文件夹
File srcFolder = new File("Test");
//2.封装目标文件夹
File targetFolder = new File("D:\\Test");
if (!targetFolder.exists()) {
targetFolder.mkdirs();
}
//进行复制
copyFolder(srcFolder, targetFolder);
System.out.println("复制完成");
}
private static void copyFolder(File srcFolder, File targetFolder) throws IOException {
//遍历源文件夹下,所有的文件,复制到目标文件夹下去
File[] files = srcFolder.listFiles();
for (File f : files) {
if(f.isFile()){
copyFiles(f, targetFolder);
}else{
File file = new File(targetFolder,f.getName());
if (!file.exists()){
file.mkdirs();
}
copyFolder(f,file);
}
}
}
//复制文件
private static void copyFiles(File f, File targetFolder) throws IOException {
//使用字节流来复制
FileInputStream in = new FileInputStream(f);//封装源文件
//封装目标文件
//File file = new File(targetFolder, f.getName());
//System.out.println(file);
FileOutputStream out = new FileOutputStream(new File(targetFolder, f.getName()));
int len = 0;
byte[] bytes = new byte[1024 * 8];
while ((len = in.read(bytes)) != -1) {
out.write(bytes, 0, len);
out.flush();
}
//释放资源
in.close();
out.close();
}
}
案例3:使用Java的IO流实现复制指定目录下指定后缀名的文件并修改名称
public class Test {
public static void main(String[] args) throws IOException {
//封装源文件夹
File srcFolder = new File("TestB");
//封装目标文件夹
File targetFolder = new File("D:\\TestB");
if (!targetFolder.exists()) {
targetFolder.mkdirs();
}
File[] files = srcFolder.listFiles();
for (File file : files) {
if (file.isFile()){
copyAndChange(file,targetFolder);
}
}
}
private static void copyAndChange(File file, File targetFolder) throws IOException {
if (file.getName().endsWith(".jpg")){
FileInputStream fileInputStream = new FileInputStream(file);
FileOutputStream fileOutputStream = new FileOutputStream(new File(targetFolder,file.getName().replace(".jpg",".png")));
byte[] bytes = new byte[1024*8];
int length=0;
while ((length=fileInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,length);
fileOutputStream.flush();
}
fileInputStream.close();
fileOutputStream.close();
}
}
}
案例4:使用Java的IO流实现键盘录入学生信息按照总分排序并写入文本文件
public class Student {
private String name;
private int chineseScore;
private int englishScore;
private int mathScore;
public Student() {
}
public Student(String name, int chineseScore, int englishScore, int mathScore) {
this.name = name;
this.chineseScore = chineseScore;
this.englishScore = englishScore;
this.mathScore = mathScore;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChineseScore() {
return chineseScore;
}
public void setChineseScore(int chineseScore) {
this.chineseScore = chineseScore;
}
public int getEnglishScore() {
return englishScore;
}
public void setEnglishScore(int englishScore) {
this.englishScore = englishScore;
}
public int getMathScore() {
return mathScore;
}
public void setMathScore(int mathScore) {
this.mathScore = mathScore;
}
public int getTotalScore(){
int sum =this.getChineseScore()+this.englishScore+this.getMathScore();
return sum;
}
@Override
public String toString() {
return this.name+"|"+this.getChineseScore()+"|"+this.englishScore+"|"+this.getMathScore()+"|"+this.getTotalScore();
}
}
public class Test {
public static void main(String[] args) throws IOException {
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getTotalScore()-s2.getTotalScore();
int num1=num==0?s1.getName().compareTo(s2.getName()):num;
return num1;
}
});
Scanner scanner = null;
int i=1;
while (i<=3){//通过改变i可以改变输入的学生总数
scanner = new Scanner(System.in);
System.out.println("请输入第"+i+"位同学的姓名");
String xm = scanner.nextLine();
System.out.println("请输入语文成绩");
int yw = scanner.nextInt();
System.out.println("请输入英语成绩");
int yy = scanner.nextInt();
System.out.println("请输入数学成绩");
int sx = scanner.nextInt();
Student stu = new Student(xm, yw, yy, sx);
treeSet.add(stu);
i++;
}
FileOutputStream fileOutputStream = new FileOutputStream("ScoreListA.txt",true);
//遍历集合,输出(写入)文档
for (Student student : treeSet) {
String string = student.toString();
byte[] bytes = string.getBytes();
fileOutputStream.write(bytes);
fileOutputStream.write("\r\n".getBytes());
fileOutputStream.flush();
}
fileOutputStream.close();
}
}