web-dev-qa-db-ja.com

CSV解析Java-動作例..?

学校用のプログラムを書きたいJava私が知らないCSVを解析するプロジェクト。各列のデータ型は知っています-区切り文字はわかりませんが。

修正方法を少しでも知らない問題は、DateまたはDateTime列を解析することです。それらは多くの形式のいずれかになります。

多くのライブラリを見つけましたが、私のニーズに最適な手がかりはありません: http://opencsv.sourceforge.net/http://www.csvreader.com/Java_csv.phphttp://supercsv.sourceforge.net/http://flatpack.sourceforge.net/

問題は、私は合計Java初心者です。これらのライブラリのどれもが必要なことを行うことができないか、それらを行うように説得することができません。

私はここに、私が必要なものをすぐに始めることができるコードサンプルを持っている人がたくさんいると確信しています:

  • 列で自動的に分割(区切り文字が不明、列タイプが既知)
  • columntypeにキャスト($、%などに対処する必要があります)
  • 日付をJava DateまたはCalendarオブジェクトに変換します

電子メールで可能な限り多くのコードサンプルを取得できたらうれしいです。

どうもありがとう!なので

17
Andy Schmidt

使用に深刻な問題があります

String[] strArr=line.split(",");

cSVファイルを解析するためです。これは、データ値内にカンマが含まれている可能性があるためです。その場合は、それらを引用符で囲む必要があり、引用符間のカンマは無視します。

これを解析する非常に簡単な方法があります:

/**
* returns a row of values as a list
* returns null if you are past the end of the input stream
*/
public static List<String> parseLine(Reader r) throws Exception {
    int ch = r.read();
    while (ch == '\r') {
        //ignore linefeed chars wherever, particularly just before end of file
        ch = r.read();
    }
    if (ch<0) {
        return null;
    }
    Vector<String> store = new Vector<String>();
    StringBuffer curVal = new StringBuffer();
    boolean inquotes = false;
    boolean started = false;
    while (ch>=0) {
        if (inquotes) {
            started=true;
            if (ch == '\"') {
                inquotes = false;
            }
            else {
                curVal.append((char)ch);
            }
        }
        else {
            if (ch == '\"') {
                inquotes = true;
                if (started) {
                    // if this is the second quote in a value, add a quote
                    // this is for the double quote in the middle of a value
                    curVal.append('\"');
                }
            }
            else if (ch == ',') {
                store.add(curVal.toString());
                curVal = new StringBuffer();
                started = false;
            }
            else if (ch == '\r') {
                //ignore LF characters
            }
            else if (ch == '\n') {
                //end of a line, break out
                break;
            }
            else {
                curVal.append((char)ch);
            }
        }
        ch = r.read();
    }
    store.add(curVal.toString());
    return store;
}

このアプローチには多くの利点があります。各キャラクターは1回だけタッチされることに注意してください。先読み、バッファのプッシュバックなどはありません。行の終わりまで先に検索し、解析する前に行をコピーしません。このパーサーはストリームからのみ機能し、各文字列値を1回作成します。ヘッダー行とデータ行で機能し、返されるリストに適切に対処します。リーダーを提供するため、選択したエンコーディングを使用して、基になるストリームが文字に変換されます。ストリームは、ファイル、HTTPポスト、HTTP getなどの任意のソースから取得でき、ストリームを直接解析します。これは静的メソッドであるため、作成および構成するオブジェクトはありません。これが返されると、保持されているメモリはありません。

このコードの完全な議論と、このアプローチがこのテーマに関する私のブログ投稿で好まれている理由を見つけることができます: CSVファイルに必要な唯一のクラス

18
AgilePro

Apache Commons CSV ライブラリもあります。おそらく必要なことを行います。 ガイド を参照してください。 2014年11月にリリース1.1に更新されました。

また、フールプルーフ版では、自分でコーディングする必要があると思います... SimpleDateFormat を使用して、形式を選択し、Dateは、事前に考えられたタイプのいずれとも異なり、Dateではありません。

18
Valentin Rocher

私のアプローチは、独自のAPIを記述することから始めることですnotです。人生は短すぎ、解決するべき差し迫った問題がさらにあります。この状況では、私は通常:

  • 私がやりたいように見えるライブラリを見つけます。存在しない場合は、then実装します。
  • ライブラリが存在するが、それが自分のニーズに適しているかどうかわからない場合は、その周りにシンアダプターAPIを記述して、その呼び出し方法を制御できるようにします。アダプターAPIは、API [〜#〜] i [〜#〜] needを表し、それらの呼び出しを基礎となるAPIにマップします。
  • ライブラリが適切でないことが判明した場合、呼び出し元に影響を与えることなく、最小限の労力でアダプタAPIの下で別のライブラリを交換できます(それが別のオープンソースのものであるか、自分で書いたものであるかを問わず)。

誰かがすでに書いたものから始めてください。オッズは、あなたが望むことをするでしょう。必要に応じて、いつでも独自のドキュメントを作成できます。 OpenCSVは、他と同じくらい良い出発点です。

7
Brian Clapper

CSVについては この仕様 をご覧ください。公式に認められた仕様はないことに留意してください。

ここで区切り文字を使用しない場合、これを行うことはできないため、何らかの方法で見つける必要があります。ファイルを手動で検査できる場合は、ファイルが何であるかをすぐに確認し、プログラムでハードコーディングする必要があります。区切り文字が変化する可能性がある場合、既知のデータのフォーマットからかどうかを推測できることが唯一の希望です。 ExcelがCSVファイルをインポートするとき、ユーザーが区切り文字を選択できるようにします。これは同様に使用できるソリューションです。

2

約5年前にcsvパーサーを使用する必要がありました。少なくとも2つのcsv標準があるようです: http://en.wikipedia.org/wiki/Comma-separated_values およびMicrosoftがExcelで行うこと。

http://ostermiller.org/utils/CSV.html の両方を食べるこのlibarayを見つけました。

2
Ray Tayek

@Brian Clapperに同意します。 SuperCSVをパーサーとして使用しましたが、結果はさまざまです。私はそれの汎用性を楽しんでいますが、自分のcsvファイルには「まだ」調整できない状況がいくつかあります。私はこの製品に信頼を寄せており、それを全体的にお勧めします。私は自分の実装で行っている単純なこと、疑いの余地はありません。

SuperCSVは、列をさまざまな形式に解析したり、列を編集したりすることができます。見てみる価値はあります。例もあり、簡単に理解できます。

私が持っている唯一の/唯一の制限は、「空の」列をキャッチし、整数または空白などに解析することです。null-pointerエラーが発生しますが、javadocsは各cellProcessorがnullを最初にチェックすることをお勧めします。だから、今のところ、まず自分を責めている。 :-)

とにかく、SuperCSVを見てください。 http://supercsv.sourceforge.net/

1
Davidson

タスクをコンポーネント部分に分解することから始めることをお勧めします。

  1. CSVから文字列データを読み取る
  2. 文字列データを適切な形式に変換する

一度それを行うと、リンクするライブラリの1つを使用するのはかなり簡単なはずです(タスク1を処理するのが最も確実です)。次に、返された値を反復処理し、各文字列値を必要な値にキャスト/変換します。

質問が文字列を異なるオブジェクトに変換する方法である場合、それはあなたがどのフォーマットで始めているのか、そしてどのフォーマットで仕上げたいのかによって異なります。

たとえば、DateFormat.parse()は、文字列から日付を解析します。特定の文字列表現のDateFormatをすばやく構築するには、SimpleDateFormatを参照してください。 Integer.parseInt()は、文字列から整数を処理します。

通貨、あなたはそれをどのようにキャプチャしたいかを決める必要があります。単にfloatとしてキャプチャする場合は、Float.parseFloat()がトリックを実行します(String.replace()を使用して、解析する前にすべての$とコンマを削除するだけです)。または、BigDecimalに解析できます(したがって、丸めの問題はありません)。通貨処理のためのより良いクラスがあるかもしれません(私はそれをあまりしませんので、JDKのその領域に精通していません)。

0
Kevin Day

基本的に、ファイルを1行ずつ読み取る必要があります。

次に、カンマなどの区切り文字で各行を分割する必要があります(CSVはコンマ区切り値を表します)。

String[] strArr=line.split(",");

これにより、文字列の配列に変換され、たとえば次のように操作できます

String name=strArr[0];
int yearOfBirth = Integer.valueOf(strArr[1]);
int monthOfBirth = Integer.valueOf(strArr[2]);
int dayOfBirth = Integer.valueOf(strArr[3]);
GregorianCalendar dob=new GregorianCalendar(yearOfBirth, monthOfBirth, dayOfBirth);
Student student=new Student(name, dob); //lets pretend you are creating instances of Student

行ごとにこれを行う必要があるため、このコードをwhileループにラップします。 (区切り文字がわからない場合は、テキストエディターでファイルを開いてください。)

0

独自のパーサーを作成するのは楽しいですが、おそらく Open CSV をご覧ください。 CSVにアクセスする多くの方法を提供し、CSVを生成することもできます。そして、doesはエスケープを適切に処理します。別の投稿で述べたように、Apache CommonsにはCSV解析ライブラリもありますが、そのライブラリはまだリリースされていません。

0
Ichthyo

少なくとも、列の区切り文字を知る必要があります。

0
Richard West