修改文本文件,在文件中每一行内容前增加行号,行号需要递增。
0、需求
修改文本文件,在文件中每一行内容前增加行号,行号需要递增。
1、分析
读取文本文件,可以使用转换流 InputStreamReader 或者使用 FileReader;
写入文本文件,可以使用转换流 OutputStreamWriter 或者使用 FileWriter。 在写入行号时,增加一个字符串的格式化操作,行号使用两位数字表示,当不足两位时,前边补0。
2、实现
2.1、字节流+转换流
即InputStreamReader + OutputStreamWriter。
因要在每行前增加行号,所以需要判断一行的开始或结束,所以我们需要了解行结束符的字节表达;
在windows机器上,行结束符为 \r\n,\n 作为一行的末尾字符,ASCII码转换为十进制就是10;
同时需要借助 StringBuilder 来临时存储当前行的内容,并把行号放到字符串的最前边,完成对行行号的写入操作。
import java.io.*; public class AddLineNumber { public static void main(String[] args) { String ori = "d:/test.txt"; new AddLineNumber().addLineNumber1(ori); } public void addLineNumber1(String ori){ long start = System.currentTimeMillis(); try( //文件读取 InputStreamReader reader = new InputStreamReader(new FileInputStream(ori)); //文件写入 OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(ori + "1.txt")); ){ int read = 0; int lineNumber = 1; StringBuilder temp = new StringBuilder(); //格式化输出,行号为两位数字,不足两位时前边补0 temp.append(String.format("%02d ", lineNumber)); while ((read = reader.read()) != -1){ //判断是否一行的结束,windows中结束符为 \r\n; \n的字节为 10 if(read != 10){ temp.append((char) read); }else { //按行更新到文件中 temp.append((char) read); writer.write(temp.toString()); writer.flush(); //重置 StringBuilder temp.setLength(0); temp.append(String.format("%02d ", ++lineNumber)); } } //因最后一行可能没有换行符,需要在这里单独处理 if(temp.length() > 0){ writer.write(temp.toString()); writer.flush(); temp.setLength(0); } long end = System.currentTimeMillis(); System.out.println(end - start); }catch (Exception e){ e.printStackTrace(); } }}注:
1、代码中没有写关闭流的语句,因为使用了 try...catch...resource 语法糖,由JVM执行关闭流的操作。
2、行号写入时,使用的字符串格式化,String.format("%02d ", lineNumber),表示使用两位数字来表示行号,如果不足两位时,前边补充0。
2.2、字符缓冲流+转换流
通过观察代码,可以发现只使用转换流和字节流,代码冗余,也不易理解,需要进行优化。
下边将通过使用字符缓冲流按行读取文本内容,增加行号后再按行写入。
import java.io.*; public class AddLineNumber { public static void main(String[] args) { String ori = "d:/test.txt"; new AddLineNumber().addLineNumber2(ori); } public void addLineNumber2(String ori){ long start = System.currentTimeMillis(); try( //文件读取 InputStreamReader reader = new InputStreamReader(new FileInputStream(ori)); BufferedReader br = new BufferedReader(reader); //文件写入 OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(ori + "2.txt")); BufferedWriter bw = new BufferedWriter(writer); ){ String read = ""; int lineNumber = 1; while ((read = br.readLine()) != null){ bw.write(String.format("%02d %s", lineNumber++, read)); bw.newLine(); } bw.flush(); long end = System.currentTimeMillis(); System.out.println(end - start); }catch (Exception e){ e.printStackTrace(); } }}注:
BufferedWriter 中的 newLine() 方法,其实就是在每行的最后加上换行符,可以不用写这句,直接在字符串的格式化末尾加上换行符 \r\n 即可,如
bw.write(String.format("%02d %s\r\n", lineNumber++, read));
2.3 字符流+字符缓冲流
相比2.1中的代码,2.2的代码相对简洁,但其实是读取文本文件,完全可以使用 Reader 和 Writer 来实现。
import java.io.*; public class AddLineNumber { public static void main(String[] args) { String ori = "d:/test.txt"; new AddLineNumber().addLineNumber3(ori); } public void addLineNumber3(String ori){ long start = System.currentTimeMillis(); try( //文件读取 BufferedReader br = new BufferedReader(new FileReader(ori)); //文件写入 PrintWriter pw = new PrintWriter(ori + "4.txt"); ){ String read = ""; int lineNumber = 1; while ((read = br.readLine()) != null){ pw.println(String.format("%02d %s", lineNumber++, read)); } pw.flush(); long end = System.currentTimeMillis(); System.out.println(end - start); }catch (Exception e){ e.printStackTrace(); } }}可以看到,在写入文件时,只创建了一个 PrintWriter 对象,不需要再使用其它处理流,这种实现方式,代码看起来最为简洁,给人一种清爽的感觉。
3、结果展示
最后来看一下实现的效果吧