文件大到用vi操作不现实。比如GB级别。主要考虑哪种方法性能最优。例子文件如下:44MB行,大小206MB。该文件只有一列。
[oracle@odilab ~]$ wc -l 3.txt
44000043 3.txt
[oracle@odilab ~]$ ls -ltrh 3.txt
-rw-r--r-- 1 oracle oinstall 206M Jan 9 10:54 3.txt
1. 删除第一行
[oracle@odilab ~]$ time sed '1d' 3.txt > 31.txt
real 0m11.590s
user 0m9.055s
sys 0m0.802s
sed为流式编辑器,会将每一行读入内存。即使只删除第一行,可以看到CPU时间占了大头,IO操作只是小部分。
同样格式的文件,增大到1.3GB后,还是用sed.
-rw-r--r-- 1 oracle oinstall 1.3G Jan 9 10:37 4.txt
[oracle@odilab ~]$ time sed '1d' 4.txt > 41.txt
real 1m4.909s
user 1m2.496s
sys 0m2.132s
文件大小:6.46倍。
流逝时间:5.6倍。
同样是sed 用-i in-place参数,差别很大。
[oracle@odilab ~]$ time sed -i '1d' 4.txt
^C
real 13m50.502s
user 8m10.900s
sys 5m29.123s
可以看到,这条命令13分钟也跑不完!
用Java实现:
import java.io.FileReader;
import java.io.FileWriter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
public class FileUtil {
private static final int BUFFER_SIZE = 1024 * 1024;
private static final String INPUT_FILE = "/home/oracle/4.txt";
private static final String OUTPUT_FILE = "/home/oracle/41.txt";
public FileUtil() {
super();
}
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter wr = null;
try {
br = new BufferedReader(new FileReader(INPUT_FILE),BUFFER_SIZE);
wr = new BufferedWriter(new FileWriter(OUTPUT_FILE), BUFFER_SIZE);
String line;
br.readLine();
while((line = br.readLine()) != null) {
wr.write(line);
wr.newLine();
}
}
catch(Exception e) {
e.printStackTrace();
}
finally {
try {
if(br != null) {
br.close();
}
if(wr != null) {
wr.close();
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}
}
[oracle@odilab ~]$ time java fileUtil
real 0m48.314s
user 0m42.635s
sys 0m3.138s
Java略胜一筹。
介绍一下Java IO几个类:
FileInputStream: 读入字节流
InputStreamReader:用指定字符集将字节流转换成字符
FileReader: 继承InputStreamReader
BufferedReader: 先将读入的字符存入缓冲区。 若没有缓冲,每一次读取操作都触发一次系统IO,程序必须等待IO完成,降低性能。有了缓冲区,将同步方式的操作转换成异步。
2. 删除最后一行
Oracle Linux带了Truncate命令。
truncate --size=<new size> <file_name>
计算出删除的行的字节数,并得到新的文件大小。新文件的大小作为第一个参数传入。