在網上碰到有網友問了這麼一道題,題目是這樣的:
java 寫入txt檔案,想要修改txt檔案每一行的第一個數字,加1;
例如txt檔案是:
1 1 5
2 2 10
3 3 15
轉變成:
2 1 5
3 2 10
4 3 15
看到題目的第一反應時可能需要正規表示式,而在java中使用raplaceAll("正規表示式","替換後的表示式")基本上就可以搞定了。但是有一個問題:正則匹配很好寫,reg = "^\\d+";就可以匹配每行的第一個數字了,但是替換成什麼呢?需要對每個數字加1,這個怎麼處理?使用捕獲組可以獲取我們需要處理的資料,但是捕獲後,無法進一步處理資料了。此條路不通之後,很不情願的想起另外一種辦法:按行處理。
掃描需要處理的文字,每掃描一行,就對該行進行匹配,匹配到資料之後,對該行處理,然後將該行寫入到新的檔案,整個文字掃描完成之後,資料也就處理完了。這個辦法是不是很笨拙?對於目前也沒有更好的方式(更好的方式也許可以使用excel來處理,但是要求使用程式設計來完成),就開始程式碼實現了:
// code version 1.0
開始寫程式碼時,發現資料之間都是以多個空格或者tab來分割,方便期間,使用split函式來處理吧。
// java 解析文字,將每行第一個數字加1
public static void writeFile() {
BufferedReader reader = null;
BufferedWriter writer = null;
try{
File file = new File( "new.txt");
if(!file.exists()) {
file.createNewFile();
}
StringBuffer sb = new StringBuffer();
reader = new BufferedReader( new FileReader("test.txt"));
String line = null;
//按行讀取
while((line = reader.readLine()) != null) {
String[] arr = line.split( "[ \t]++");
if(arr. length < 3) {
sb.append(line).append( "\r\n");
continue;
}
//獲取第一個數字,並加1
int num = Integer. valueOf(arr[0]);
num ++;
sb.append(num).append( "\t").append(arr[1]).append( "\t").append(arr[2]).append( "\r\n");
}
//寫入新的檔案
writer = new BufferedWriter( new FileWriter(file));
writer.write(sb.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(reader != null) {
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(writer != null) {
try {
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
程式碼寫起來還是很順利的,但是有個問題,在資料處理完成之後:
int num = Integer.valueOf(arr[0]);
num ++;
怎麼把新的內容寫入到當前行中,也就是寫入當前的文字中?處理資料的時候是通過reader來按行讀取,如果需要將資料寫入的話,需要writer,在讀取檔案的時候,直接使用writer寫入資料,也不是件很容易的事。為了方便處理,果斷建立一個新的檔案,寫入新的資料,處理完之後,刪掉舊的檔案就是!
程式碼實現之後,就跟一個朋友商討了下,朋友說,可以使用正則來完成,split的效率有點低。OK,把主要的處理過程重新實現了下:
// code version 1.1
Pattern pattern = Pattern. compile("^\\d+" );
while(...) {
Matcher matcher = pattern .matcher(line);
if(matcher.find()) {
String str = matcher.group();
int n = Integer.parseInt(str);
n ++;
line = line.replaceFirst(str, String.valueOf(n));
sb.append(line).append( "\r\n");
}
}
除了將split修改為Pattern之後,同時,行資料也保持原來的風格保持了不變:
line = line.replaceFirst(str, String.valueOf(n));
但是為什麼Pattern會比split的效率高呢?
split的實現中,會呼叫Pattern.compile("...");也就是在對文字每行的處理中,如果使用split,則每次都會新建一個Pattern.compile("...")物件。而在使用Pattern類,只在最開始生成一個Pattern.compile("...")物件,減少了記憶體的開銷;
一個前輩說,不需要正則,使用indexOf和substring可以提高效率。同時,他建議不要使用BufferedWriter,應當使用printStream。
恩,開始修改程式碼:
// code version 1.2
public static void writeFile() throws IOException {
BufferedReader reader = null;
PrintStream writer = null;
File file = new File( "new.txt");
if(!file.exists()) {
file.createNewFile();
}
writer = new PrintStream( new FileOutputStream(file));
reader = new BufferedReader( new FileReader("test.txt" ));
String line = null;
//按行讀取
while((line = reader.readLine()) != null) {
//這裡通過index來確定需要處理的資料
int index = line.indexOf( " ");
if(index == -1) {
continue;
}
int num = Integer.parseInt(line.substring(0,index))+1;
line = num + line.substring(index);
writer.println(line);
}
// ....
}
使用indexOf和substring 替換掉正則之後,邏輯似乎也清晰了許多,由於去掉了正規表示式的一些處理,直接對字串處理,效率上應該會有一些提高。但是使用PrintStream 替換掉BufferedWriter是不是就是個好主意?不見得,BufferedWriter作為一個具有緩衝功能的包裝類,效能上比其他類要高很多。而且在處理文字時,每處理一行,就向檔案中寫入資料,這個效能也不見得很高。權衡之際,提高處理資料效率,使用indexOf和substring,寫檔案時,採用BufferedWriter將資料寫入緩衝,提高效率。
// code version 1.3
public static void writeFile() throws IOException {
BufferedReader reader = null;
BufferedWriter writer = null;
writer = new BufferedWriter( new FileWriter("new.txt" ));
reader = new BufferedReader( new FileReader("test.txt" ));
String line = null;
//按行讀取
while((line = reader.readLine()) != null) {
//這裡通過index來確定需要處理的資料
int index = line.indexOf( " ");
if(index == -1) {
continue;
}
int num = Integer.parseInt(line.substring(0,index))+1;
line = num + line.substring(index);
writer.write(line);
writer.newLine();
}
//...
}
到此,關於該題目的編碼總算塵埃落定。期間,經歷了幾番波折,從split->Pattern->indexOf再到流的選取,糾結了較長時間。總結一下:
1、儘量不要使用正規表示式,可以使用indexOf和substring來代替正則;必須使用正則的情況下,使用Pattern類能夠提高效率。
2、使用Buffer之類的包裝類,可以提高效率。
但是,還是有幾個問題留作以後慢慢考慮吧。
1、直接使用正則或者是否還有其他更簡單的處理方式麼?
2、如何直接寫入到當前的檔案中?