JavaでCSVファイルを読み込んで解析する方法

country-csv-example、width = 592、height = 206

カンマ区切り値(CSV)ファイルは通常のプレーンテキストファイルで、列単位でデータを格納し、セパレータで区切ります(通常はカンマ「、」など)。

例えば ​​:

1,US,United States
2,MY,Malaysia
3,AU,Australia

または

"1","US","United States"
"2","MY","Malaysia"
"3","AU","Australia"

CSVファイルには、通常2つの問題があります。

{空} 1。セパレータを含むフィールド(たとえば、セパレータ)はカンマで、フィールドにはカンマが入ります。

"aaa","b,bb","ccc"

{空} 2。二重引用符は、フィールドを囲み、二重引用符を含むフィールドに使用されます。これを解決するには、フィールド内に現れる二重引用符を別の二重引用符(https://tools.ietf.org/html/rfc4180[RFC4180)で前に置いてエスケープする必要があります

"aaa","b""bb","ccc"

このチュートリアルでは、CSVファイルから値を読み取り、解析して印刷する3つの例を示します。

  1. 簡単なフォーマットのCSVファイルを解析するためのシンプルなソリューション.

  2. 奇妙なフォーマットのCSVファイルを解析するための高度なソリューション(

セパレータまたは二重引用符) 。サードパーティのソリューション、OpenCSVの例

1.簡単な解決策

CSVファイルに "区切り文字または二重引用符"が含まれていないことが分かっている場合は、標準の `split()`を使用してCSVファイルを解析してください。

1.1単純なCSVファイルを確認する

/Users/mkyong/csv/country.csv

"1.0.0.0","1.0.0.255","16777216","16777471","AU","Australia"
"1.0.1.0","1.0.3.255","16777472","16778239","CN","China"
"1.0.4.0","1.0.7.255","16778240","16779263","AU","Australia"
"1.0.8.0","1.0.15.255","16779264","16781311","CN","China"
"1.0.16.0","1.0.31.255","16781312","16785407","JP","Japan"
"1.0.32.0","1.0.63.255","16785408","16793599","CN","China"
"1.0.64.0","1.0.127.255","16793600","16809983","JP","Japan"
"1.0.128.0","1.0.255.255","16809984","16842751","TH","Thailand"

1.2マジックはありません。テキストファイルの上に読み込んでカンマ区切りで区切ります。

CSVReader.csv

package com.mkyong.csv;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class CSVReader {

    public static void main(String[]args) {

        String csvFile = "/Users/mkyong/csv/country.csv";
        BufferedReader br = null;
        String line = "";
        String cvsSplitBy = ",";

        try {

            br = new BufferedReader(new FileReader(csvFile));
            while ((line = br.readLine()) != null) {

               //use comma as separator
                String[]country = line.split(cvsSplitBy);

                System.out.println("Country[code= " + country[4]+ " , name=" + country[5]+ "]");

            }

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

}

1.3 JDK 7以上では、try-resourcesを使用します。

CSVReader.csv

package com.mkyong.csv;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class CSVReader {

    public static void main(String[]args) {

        String csvFile = "/Users/mkyong/csv/country.csv";
        String line = "";
        String cvsSplitBy = ",";

        try (BufferedReader br = new BufferedReader(new FileReader(csvFile))) {

            while ((line = br.readLine()) != null) {

               //use comma as separator
                String[]country = line.split(cvsSplitBy);

                System.out.println("Country[code= " + country[4]+ " , name=" + country[5]+ "]");

            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

出力

Country[code= "AU" , name="Australia"]Country[code= "CN" , name="China"]Country[code= "AU" , name="Australia"]Country[code= "CN" , name="China"]Country[code= "JP" , name="Japan"]Country[code= "CN" , name="China"]Country[code= "JP" , name="Japan"]Country[code= "TH" , name="Thailand"]....

===  2.アドバンスソリューション

このソリューションは、 "セパレータまたは二重引用符"の問題を含むフィールドを解決し、カスタムセパレータおよびカスタム囲まれたフィールドもサポートします。次のCSV解析の例とJUnitのテストケースを見て、その動作を理解してください。

**  Note **  +また、フィールド内に現れる二重引用符が、別の二重引用符で前に置かれてエスケープされなければならない場合

"aaa","b""bb","ccc"

2.1別のCSVファイルを確認する

/Users/mkyong/csv/country2.csv

10,AU,Australia 11,AU,Aus""tralia "12","AU","Australia" "13","AU","Aus""tralia" "14","AU","Aus,tralia"

2.2以下の例は、この記事「https://agiletribe.wordpress.com/2012/11/23/the-only-class-you-need-for-csv-files/[CSVに必要なクラスのみ(他の機能をサポートするように固定されていますが、 "固定コメント"を読んでください)、またこのサードパーティのhttp://opencsv.sourceforge.net/[OpenCSV]ライブラリを参照してください。

CSVUtils.java

package com.mkyong.utils;

import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Scanner;

public class CSVUtils {

private static final char DEFAULT__SEPARATOR = ',';
private static final char DEFAULT__QUOTE = '"';
public static void main(String[]args) throws Exception {
String csvFile = "/Users/mkyong/csv/country2.csv";
Scanner scanner = new Scanner(new File(csvFile));
while (scanner.hasNext()) {
    List<String> line = parseLine(scanner.nextLine());
    System.out.println("Country[id= " + line.get(0) + ", code= " + line.get(1) + " , name=" + line.get(2) + "]");
}
scanner.close();
}
public static List<String> parseLine(String cvsLine) {
    return parseLine(cvsLine, DEFAULT__SEPARATOR, DEFAULT__QUOTE);
}
public static List<String> parseLine(String cvsLine, char separators) {
    return parseLine(cvsLine, separators, DEFAULT__QUOTE);
}
public static List<String> parseLine(String cvsLine, char separators, char customQuote) {
List<String> result = new ArrayList<>();
//if empty, return!
 if (cvsLine == null && cvsLine.isEmpty()) {
     return result;
 }
if (customQuote == ' ') {
    customQuote = DEFAULT__QUOTE;
}
if (separators == ' ') {
    separators = DEFAULT__SEPARATOR;
}
StringBuffer curVal = new StringBuffer();
boolean inQuotes = false;
boolean startCollectChar = false;
boolean doubleQuotesInColumn = false;
char[]chars = cvsLine.toCharArray();
for (char ch : chars) {
if (inQuotes) {
    startCollectChar = true;
    if (ch == customQuote) {
        inQuotes = false;
        doubleQuotesInColumn = false;
    } else {
//Fixed : allow "" in custom quote enclosed
 if (ch == '\"') {
     if (!doubleQuotesInColumn) {
         curVal.append(ch);
         doubleQuotesInColumn = true;
     }
 } else {
     curVal.append(ch);
 }
    }
} else {
    if (ch == customQuote) {
inQuotes = true;
//Fixed : allow "" in empty quote enclosed
 if (chars[0]!= '"' && customQuote == '\"') {
     curVal.append('"');
 }
//double quotes in column will hit this!
 if (startCollectChar) {
     curVal.append('"');
 }
} else if (ch == separators) {
result.add(curVal.toString());
curVal = new StringBuffer();
startCollectChar = false;
    } else if (ch == '\r') {
       //ignore LF characters
        continue;
    } else if (ch == '\n') {
       //the end, break!
        break;
    } else {
        curVal.append(ch);
    }
}
}
result.add(curVal.toString());
    return result;
}

}

出力

Country[id= 10, code= AU , name=Australia]Country[id= 11, code= AU , name=Aus"tralia]Country[id= 12, code= AU , name=Australia]Country[id= 13, code= AU , name=Aus"tralia]Country[id= 14, code= AU , name=Aus,tralia]…​.

3.3次のユニットテストを見直し、 "カンマと二重引用符"の問題をテストします。

CSVUtilsTest.java

package com.mkyong.csv;

import com.mkyong.utils.CSVUtils;
import org.hamcrest.core.IsNull;
import org.junit.Test;

import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;

public class CSVUtilsTest {

    @Test
    public void test__no__quote() {

        String line = "10,AU,Australia";
        List<String> result = CSVUtils.parseLine(line);

        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Australia"));

    }

    @Test
    public void test__no__quote__but__double__quotes__in__column() throws Exception {

        String line = "10,AU,Aus\"\"tralia";

        List<String> result = CSVUtils.parseLine(line);
        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Aus\"tralia"));

    }

    @Test
    public void test__double__quotes() {

        String line = "\"10\",\"AU\",\"Australia\"";
        List<String> result = CSVUtils.parseLine(line);

        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Australia"));

    }

    @Test
    public void test__double__quotes__but__double__quotes__in__column() {

        String line = "\"10\",\"AU\",\"Aus\"\"tralia\"";
        List<String> result = CSVUtils.parseLine(line);

        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Aus\"tralia"));

    }

    @Test
    public void test__double__quotes__but__comma__in__column() {

        String line = "\"10\",\"AU\",\"Aus,tralia\"";
        List<String> result = CSVUtils.parseLine(line);

        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Aus,tralia"));

    }

}

3.4別の単体テストを見直し、カスタムセパレータとカスタム囲まれたフィールドをテストします。

CSVUtilsTestCustom.java

package com.mkyong.csv;

import com.mkyong.utils.CSVUtils;
import org.hamcrest.core.IsNull;
import org.junit.Test;

import java.util.List;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;

public class CSVUtilsTestCustom {

    @Test
    public void test__custom__separator() {

        String line = "10|AU|Australia";
        List<String> result = CSVUtils.parseLine(line, '|');

        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Australia"));

    }

    @Test
    public void test__custom__separator__and__quote() {

        String line = "'10'|'AU'|'Australia'";
        List<String> result = CSVUtils.parseLine(line, '|', '\'');

        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Australia"));

    }

    @Test
    public void test__custom__separator__and__quote__but__custom__quote__in__column() {

        String line = "'10'|'AU'|'Aus|tralia'";
        List<String> result = CSVUtils.parseLine(line, '|', '\'');

        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Aus|tralia"));

    }

    @Test
    public void test__custom__separator__and__quote__but__double__quotes__in__column() {

        String line = "'10'|'AU'|'Aus\"\"tralia'";
        List<String> result = CSVUtils.parseLine(line, '|', '\'');

        assertThat(result, IsNull.notNullValue());
        assertThat(result.size(), is(3));
        assertThat(result.get(0), is("10"));
        assertThat(result.get(1), is("AU"));
        assertThat(result.get(2), is("Aus\"tralia"));

    }

}

3. OpenCSVの例

上のシンプルで先進的なソリューションに不満がある場合は、サードパーティのCSVライブラリ(http://opencsv.sourceforge.net/[OpenCSV)を使用してみてください。

3.1 Maven。

pom.xml

    <dependency>
        <groupId>com.opencsv</groupId>
        <artifactId>opencsv</artifactId>
        <version>3.8</version>
    </dependency>

3.2 CSVファイルを確認します。

/Users/mkyong/csv/country3.csv

10,AU,Australia
11,AU,Aus""tralia
"12","AU","Australia"
"13","AU","Aus""tralia"
"14","AU","Aus,tralia"

3.2 CSVファイルを解析するOpenCSVの例。

CSVReaderExample.java

package com.mkyong.csv;

import com.opencsv.CSVReader;

import java.io.FileReader;
import java.io.IOException;

public class CSVReaderExample {

    public static void main(String[]args) {

        String csvFile = "/Users/mkyong/csv/country3.csv";

        CSVReader reader = null;
        try {
            reader = new CSVReader(new FileReader(csvFile));
            String[]line;
            while ((line = reader.readNext()) != null) {
                System.out.println("Country[id= " + line[0]+ ", code= " + line[1]+ " , name=" + line[2]+ "]");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


    }

}

出力

Country[id= 10, code= AU , name=Australia]Country[id= 11, code= AU , name=Aus"tralia]Country[id= 12, code= AU , name=Australia]Country[id= 13, code= AU , name=Aus"tralia]Country[id= 14, code= AU , name=Aus,tralia]....

** 注意** その他の例については、このhttp://opencsv.sourceforge.net/[OpenCSV公式文書]を参照してください。

完了しました。

=== 参考文献

.  https://agiletribe.wordpress.com/2012/11/23/the-only-class-you-need-for-csv-files/[The

CSVファイルに必要なクラスのみ]。 https://github.com/agilepro/mendocino/blob/master/src/org/workcast/streams/CSVHelper.java[CSVHelper

例]。 http://ostermiller.org/utils/CSV.html[Ostermiller Javaユーティリティ -

カンマ区切り値(CSV)]。 https://tools.ietf.org/html/rfc4180[RFC4180  - のフォーマット

カンマ区切り値(CSV)]。 http://opencsv.sourceforge.net/[OpenCSVウェブサイト]

.  link://java/how-to-export-data-to-csv-file-java/[Java  - エクスポートする方法

データをCSVファイルに書き込む]

link://タグ/csv/[csv]link://タグ/java/[java]