1. 程式人生 > >關於CSV檔案的讀寫問題(特別是有雙引號和逗號的情況)(轉載)

關於CSV檔案的讀寫問題(特別是有雙引號和逗號的情況)(轉載)

最新專案中遇到CVS中有特殊字元(英文逗號、引號),導致解析出現問題,度娘一把查詢到解決辦法,記錄一下

轉載:https://blog.csdn.net/xyr05288/article/details/53696464

一. 對於CSV的讀寫既可以像讀寫txt檔案似的讀寫

/*===================讀檔案=======================*/
InputStreamReader read = new InputStreamReader(
new FileInputStream(file),encoding);//考慮到編碼格式
BufferedReader bufferedReader = new
BufferedReader(read); String lineTxt; while((lineTxt = bufferedReader.readLine()) != null ){ if(!lineTxt.trim().equals("")) { String[] temp = lineTxt.split("\t",-1); txtList.add(temp); } } read.close(); /*==================寫檔案========================*/ File txtFile = new
File(filePath); //追加 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(txtFile, true),encoding)); if(content != null && content.size()>0){ for(Integer i=0 ; i<content.size(); i++){ String[] element = content.get(i);//一行元素 if(element != null
&& element.length > 0){ for(Integer j=0; j<element.length; j++){ String temp = element[j]; if(j == element.length - 1){ bw.write(temp + "\n"); }else{ bw.write(temp + separator); } } } }

也可以用java提供的庫javacsv和opencsv寫,但是注意javacsv不可追加,中文OK;opencsv可追加,但是中文會亂碼。兩者可寫入欄位中含有逗號的內容。

二. 用寫txt檔案的方式寫csv時,針對內容中的逗號和雙引號要做特殊處理(參考文章):

CSV全稱是:Comma Separated Values 或者 Character Separated Values。

儘管第一種說法更常見,但我覺得還是第二種說法更確切一些,因為你可以使用其它字元做分隔符。

使用逗號做分隔符的CSV檔案有一個好處:你可以直接用Excel開啟。如果使用其它分隔符,比如“|”,你必須告訴Excel該檔案使用“|”作分隔符,Excel才能把它匯入進來。

前幾天,project manager告訴我:我們有許多CSV檔案,都是使用“|”做分隔符,用Excel開啟的時候比較麻煩,使用者想在Excel中直接開啟。這樣就需要使用“,”做分隔符。但是檔案中有些欄位含有逗號,必須對這些逗號特殊處理,才能保證CSV檔案在Excel中正確開啟。他還給了我一個演算法:

如果欄位中有逗號(,),該欄位使用雙引號(”)括起來;

如果該欄位中有雙引號,該雙引號前要再加一個雙引號,然後把該欄位使用雙引號括起來。

看完project manager的要求,我真是滿頭起包啊。在IT業混了十幾年了,竟然不知道這樣處理逗號。 
舉幾個例子: 

欄位處理前欄位處理後
abc,d2"abc,d2"
ab"c,d2"ab""c,d2"
"abc"""abc"
""""""""

如果欄位中有兩個挨著的雙引號,比如:aaa”“ccc。這種情況不用特殊處理。這是我在寫這篇部落格的時候才想起來的,趕忙使用Excel測試了一下。還好,不用特殊處理就能正常開啟,不然我還得改程式。當然了,如果你把它處理成:”aaa”“”“ccc” Excel也能正常開啟。事後總結總結真是有好處啊。

另外,如果某欄位第一個字元是空格,第二個字元是雙引號,這種情況不用特殊處理。Project Manager在給我描述演算法的時候,也舉了一個欄位只有一個雙引號的例子,但他不小心在雙引號前面加了個空格,把問題掩蓋過去了。

因此在寫CSV檔案時,需要先判斷是否有逗號和雙引號,並做相應處理

boolean quoteFlag = false;//標記是否新增過雙引號
//20161214 若發現有逗號  需前後加引號 否則會出現串列的情況
String value = element[i];
if(value.contains("\"")){ //若發現有雙引號  需要將字串中的一個雙引號替換為兩個 並且需前後加雙引號
        value = value.replaceAll("\"","\"\"");
        value = "\"" + value + "\"";
        quoteFlag = true;
 }
 if(value.contains(",") && !quoteFlag){ //若發現有逗號  需前後加引號
        value = "\"" + value + "\"";
 }

if(j == fileHeader.size() - 1){
         bw.write(value + "\n");
 }else{
         bw.write(value + separator);
 }

讀這樣的csv檔案時,需要做類似的處理:

//去掉字串前後字串 for csv輸出
public static String clearStartAndEndQuote(String str){
        if(str != null && str.length()>=2) {
            if(str.indexOf("\"")==0) str = str.substring(1,str.length());   //去掉第一個 "
            if(str.lastIndexOf("\"")==(str.length()-1)) str = str.substring(0,str.length()-1);  //去掉最後一個 "

            str = str.replaceAll("\"\"","\"");//把兩個雙引號換成一個雙引號
        }
        return str;
 }

String tempValue = ClassUtil.clearStartAndEndQuote(temp[j]);

三. 文字內容的逗號分隔(參考文章)

當大家進行這一操作的時候通常會遇到如下問題。 
1: 想分割資料 例如:

"123","Jack jona","Computer science"
"234","Joen Dan", "Philosophy"

//當遇到這種資料的時候可直接用 逗號進行分割。

String[] strArr = str.trim().split(",",-1); 

2: 分割資料如下:

"123", "jack jona", "New York, NY"
"234", "Lee Jack", "Fort myers, FL"

//當遇到這種資料的時候可以直接使用

String[] strArr = str.trim().split(",(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)",-1); //雙引號內的逗號不分割  雙引號外的逗號進行分割

//進行分割。 這種的好處是隻對引號外面的逗號進行分割,對引號內的不分割。 
//簡單的說這種分割得出的結果是 
123| jack jona| New York, NY 
234| Lee Jack| Fort myers, FL