字节流可以处理任意类型数据
字符流只能处理纯文本
字符流读取字符,就要先读取到字节数据,然后转换为字符,如果要写出字符,要把字符转成字节再写出去。
拷贝纯文本字节流比字符流更好:
操作纯文本的时候字符流在只读(一次读取一个字符)和只写(可以直接写出字符串(底层把字符转化为字节数组写出去了)表面不用转换,而字节流需要转化为字节数组)的时候好用。
字符流拷贝非纯文本文件和拷贝纯文本文件是一样的,需要先将字节转换为字符,转换字符如果没有成功就会变成?,写出去的时候也写的是?
package day21;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
public class Dk1ReverseTxt {
//将文本文档文本反转,第一行和倒数第一行交换,第二行和倒数第二行交换
//流对象尽量晚开早关,为了节省内存
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//将数据存到集合再反转
ArrayList<String> list = new ArrayList<String>();
String line;
while((line = br.readLine()) != null) { //一次读取一行
list.add(line); //将读到的字符串存储到集合
}
br.close();
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt")); //会先清空a.txt再写
//倒着遍历
for (int i = list.size()-1; i >= 0; i--) {
bw.write(list.get(i));
bw.newLine(); //写入行分隔符
}
bw.close();
}
}
package day21;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
public class Dk2LineNumberReader {
//LineNumberReader
//通过setLineNumber()和getLineNumber()方法知道肯定有lineNumber,当readLine()一次
//,lineNumber就自身+1一次,所以每次getLineNumber()是变化的
public static void main(String[] args) throws IOException {
LineNumberReader lnr = new LineNumberReader(new FileReader("a.txt"));
String line;
lnr.setLineNumber(100); //从第101行开始读数据
while((line = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + ":" + line); //可以添加行号
}
lnr.close();
}
}
字节流转换为字符流
转换流原理图:
加缓冲区原理图:
package day21;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.TreeMap;
public class Dk4Counts {
//统计文本中字符出现的个数并写入文件
public static void main(String[] args) throws IOException {
BufferedReader fr = new BufferedReader(new FileReader("a.txt"));
TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
int ch;
while((ch = fr.read()) != -1) { //字符提升为int类型
char c = (char)ch; //int类型强转为char
// if (!tm.containsKey(c)) { //不包含c,就添加第一个到TreeMap
// tm.put(c,1);
// }else
// tm.put(c, tm.get(c)+1);
//或者用三目运算符
tm.put(c,!tm.containsKey(c) ? 1:tm.get(c)+1 ); //会按照字典顺序排序
}
fr.close();
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
for (Character key : tm.keySet()) {
switch (key) {
case '\t':
bw.write("\\t" + "=" + tm.get(key)); //转义,这样显示的就是\t
break;
case '\n':
bw.write("\\n" + "=" + tm.get(key)); //转义,这样显示的就是\n
break;
case '\r':
bw.write("\\r" + "=" + tm.get(key)); //转义,这样显示的就是\r
break;
default:
bw.write(key + "=" + tm.get(key));
break;
}
bw.newLine(); //换行
}
bw.close();
}
}
package day21;
import java.io.File;
import java.util.Scanner;
public class Dk5Counts {
//录入文件夹路径,统计文件夹大小,还可以删除该文件夹
public static void main(String[] args) {
File dir = getDir();
System.out.println(getFileLength(dir));
deleteFile(dir);
}
//键盘录入一个文件路径
public static File getDir() {
Scanner scanner = new Scanner(System.in);
while(true) {
String line = scanner.nextLine();
File dir = new File(line);
if (!dir.exists()) { //判断是否存在
System.out.println("重输");
}else if (dir.isFile()) { //判断是否是文件
System.out.println("重输");
}else {
return dir; //返回文件夹路径
}
}
}
//统计文件夹大小
public static Long getFileLength(File dir) {
long len = 0;
File[] subFiles = dir.listFiles(); //获取dir路径下的所有文件和文件夹
for (File file : subFiles) {
if(file.isFile()) { //是否为文件
len = len + file.length();
}else { //是文件夹
len = len + getFileLength(file);
}
}
return len;
}
//删除文件夹(delete只能删除空文件夹)
public static void deleteFile(File dir) {
File[] file = dir.listFiles();
for (File f : file) {
if (f.isFile()) { //文件就直接删除
f.delete();
}else { //是路径
deleteFile(f);
}
}
dir.delete(); //就会把已经删除完的空文件夹删除,否则会留下一个空文件夹
}
}