6

Apache Commons CSV 1.2 を使用して Java で解析している 37 列の CSV ファイルがあります。私のセットアップコードは次のとおりです。

//initialize FileReader object
FileReader fileReader = new FileReader(file);

//intialize CSVFormat object
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING);

//initialize CSVParser object
CSVParser csvFileParser = new CSVParser(fileReader, csvFileFormat);

//Get a list of CSV file records
List<CSVRecord> csvRecords = csvFileParser.getRecords();

// process accordingly

私の問題は、処理する CSV をターゲット ディレクトリにコピーして解析プログラムを実行すると、次のエラーが発生することです。

Exception in thread "main" java.lang.IllegalArgumentException: Index for header 'Title' is 7 but CSVRecord only has 6 values!
        at org.apache.commons.csv.CSVRecord.get(CSVRecord.java:110)
        at launcher.QualysImport.createQualysRecords(Unknown Source)
        at launcher.QualysImport.importQualysRecords(Unknown Source)
        at launcher.Main.main(Unknown Source)

ただし、ファイルをターゲット ディレクトリにコピーし、開いて保存し、プログラムを再試行すると、機能します。CSV を開いて保存すると、最後に必要なコンマが追加されるため、プログラムは、読み取るヘッダーが不足していることに不満を抱くことはありません。

コンテキストとして、保存前/保存後のサンプル行を次に示します。

変更前 (失敗): "data","data","data","data"

後 (作業中): "data","data",,,,"data",,,"data",,,,,,

私の質問: CSV 形式を開いて保存すると、なぜ CSV 形式が変わるのですか? 値やエンコーディングは変更していません。保存時の動作は、MS-DOS または通常の .csv 形式と同じです。また、テストではExcelを使用してコピー/開く/保存しています。

使用する必要があるエンコーディングまたはフォーマット設定はありますか? これをプログラムで解決できますか?

前もって感謝します!

編集#1:

追加のコンテキストとして、元のファイルで最初に空の行を表示すると、次のような改行 ^M 文字が含まれています。

^M

Excel で開いて保存すると、37 個の空のフィールドがすべて次のようになります。

,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,^M

これは Windows エンコーディングの不一致ですか?

4

3 に答える 3

2

おそらく、最初にファイルを生成したものとの互換性の問題です。Excelは、空白行を各列に空の文字列を持つ有効な行として受け入れ、列の数が他の行と一致するようです。次に、列区切り文字を使用して CSV 規則に従って保存します。(^M はキャリッジ リターン文字です。Microsoft システムでは、テキスト ファイルの行末のライン フィード文字の前にあります)。

おそらく、独自のReaderサブクラスを作成して FileReader と CSVParser の間に配置することで対処できます。リーダーは行を読み取り、空白の場合は正しい数のコンマを含む行を返します。それ以外の場合は、行をそのまま返します。

例えば:

class MyCSVCompatibilityReader extends BufferedReader
    {
    private final BufferedReader delegate;

    public MyCSVCompatibilityReader(final FileReader fileReader)
        {
        this.delegate = new BufferedReader(fileReader);
        }

    @Override
    public String readLine()
        {
        final String line = this.delegate.readLine();
        if ("".equals(line.trim())
            { return ",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"; }
        else
            { return line; }
        }
    }

インターフェースを実装する際に、正しく実装する必要がある詳細は他にもたくさんあります。他のすべてのメソッド (close、ready、reset、skip など) への呼び出しをパススルーし、さまざまなread()メソッドのそれぞれが正しく機能することを確認する必要があります。ファイルが簡単にメモリに収まる場合は、ファイルを読み取り、修正されたバージョンを新しいStringWriterに書き込んでから、CSVParser にStringReaderを作成する方が簡単かもしれません。

于 2016-04-15T21:05:56.223 に答える
-1

多分これを試してください: 指定されたファイルのパーサーを作成します。parse(ファイル file, Charset charset, CSVFormat format)

//import import java.nio.charset.StandardCharsets; //StandardCharsets.UTF_8

注: このメソッドは、FileReader.FileReader(java.io.File) を使用して FileReader を内部的に作成します。FileReader は、コードを実行している JVM のデフォルトのエンコーディングに依存します。

于 2016-04-15T17:40:24.270 に答える
-1

または、AllowMissingColumnNames を試してみてください。

//intialize CSVFormat object 
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING).withAllowMissingColumnNames();
于 2016-04-15T18:10:42.247 に答える