IO流应用:在文本文件前增加行号

时间:2023-02-02 13:00:51

修改文本文件,在文件中每一行内容前增加行号,行号需要递增。

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、结果展示

最后来看一下实现的效果吧

IO流应用:在文本文件前增加行号