昔作成して公開している CSVの読み書き、
GitHub - yipuran/yipuran-csv: Java CSV read and write
これは、TSV ファイルで使用することを目的にしていなかった。
長いこと開発をしていて、なかなかTSVファイルを対象にすることが少なかった。
この yipuran-csv の中の、Csvprocess と同じ機能で、TSV読込みは、継承をすることで
次のように用意できる。
Csvprocess の説明は、→ こちらのWiki
継承して、TSV用に用意するポイントは、
- 内部で使用する org.yipuran.csv4j.CSVReader のインスタンス生成で、デリミタをカンマ区切りからタブ区切りにすること
後は、Csvprocess と同じメソッドの仕様で使える。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Stream; import org.yipuran.csv.BOMfunction; import org.yipuran.csv.Csvprocess; import org.yipuran.csv4j.CSVReader; import org.yipuran.csv4j.ParseException; import org.yipuran.csv4j.ProcessingException; /** * Tsvprocess : Csvprocessを継承したTSV読込クラス */ public class Tsvprocess extends Csvprocess{ private boolean blankIsNull = false; private static final char DELIMITER = '\t'; public Tsvprocess(){} public Tsvprocess(boolean blankIsNull) { this.blankIsNull = blankIsNull; } /** * ヘッダ有りTSV読込み実行. * @param inReader InputStreamReader * @param header ヘッダ行 Consumer * @param processor コンテンツ行BiConsumer、TSV行読込みカウント(1始まり)とTSV文字列のList * @throws IOException * @throws ProcessingException */ @Override public void read(InputStreamReader inReader, Consumer<List<String>> header, BiConsumer<Integer, List<String>> processor) throws IOException, ProcessingException{ CSVReader reader = new CSVReader(new BufferedReader(inReader), Charset.forName(inReader.getEncoding()), DELIMITER, getComment(), blankIsNull); try{ int lineCount = 0; while(true){ try{ List<String> fields = reader.readLine(); if (fields.size()==0) break; if (isHasHeader() && lineCount==0){ String rep = fields.get(0); if (BOMfunction.match(rep)) { fields.remove(0); fields.add(0, BOMfunction.chop(rep)); } header.accept(fields); }else{ processor.accept(lineCount, fields); } }catch(Exception e){ throw new ProcessingException(e, reader.getLineNumber()); } lineCount++; } }finally{ reader.close(); } } /** * ヘッダ無しTSV読込み実行. * @param inReader InputStreamReader * @param processor BiConsumer 行のindexとTSV文字列のList * @throws IOException * @throws ProcessingException * @throws ParseException */ @Override public void readNoheader(InputStreamReader inReader, BiConsumer<Integer, List<String>> processor) throws IOException, ProcessingException, ParseException{ CSVReader reader = new CSVReader(new BufferedReader(inReader), Charset.forName(inReader.getEncoding()), DELIMITER, getComment(), blankIsNull); try{ int lineIndex = 0; while(true){ try{ List<String> fields = reader.readLine(); if (fields.size()==0) break; if (lineIndex==0){ String rep = fields.get(0); if (BOMfunction.match(rep)) { fields.remove(0); fields.add(0, BOMfunction.chop(rep)); } } processor.accept(lineIndex, fields); }catch(Exception e){ throw new ProcessingException(e, reader.getLineNumber()); } lineIndex++; } }finally{ reader.close(); } } /** * ヘッダ有りTSV読込み実行(Map形式読込み). * <PRE> * ヘッダ行列をキーとして読込み結果をMapで実行 * </PRE> * @param inReader InputStreamReader * @param processor コンテンツ行BiConsumer、TSV行読込みカウント(1始まり)とヘッダのキーに対するコンテンツ行の値のMap * @throws IOException * @throws ProcessingException */ @Override public void read(InputStreamReader inReader, BiConsumer<Integer, Map<String, String>> processor) throws IOException, ProcessingException{ CSVReader reader = new CSVReader(new BufferedReader(inReader), Charset.forName(inReader.getEncoding()), DELIMITER, getComment(), blankIsNull); try{ Map<Integer, String> headerMap = new HashMap<>(); int lineCount = 0; while(true){ try{ List<String> fields = reader.readLine(); if (fields.size()==0) break; if (isHasHeader() && lineCount==0){ String rep = fields.get(0); if (BOMfunction.match(rep)) { fields.remove(0); fields.add(0, BOMfunction.chop(rep)); } int i = 0; for(String key:fields){ headerMap.put(i, key); i++; } }else{ processor.accept(lineCount, Stream.iterate(0, i->i+1).limit(fields.size()) .collect(HashMap<String, String>::new, (r, t)->r.put(headerMap.get(t), fields.get(t)), (r, t)->{}) ); } }catch(Exception e){ throw new ProcessingException(e, reader.getLineNumber()); } lineCount++; } }finally{ reader.close(); } } }
この Tsvprocess を使用するサンプルは、、、
文字コード=UTF-8 で1行目はヘッダ行で読込み
↓ サンプル無いの in変数は、InputStream
Tsvprocess process = new Tsvprocess(); process.read(in, StandardCharsets.UTF_8 , h->{ // h=List<String> ヘッダ行 }, (i, p)->{ // i=TSV行番号:1始まり、 p=1行の List<String> });
文字コード=UTF-8 でヘッダ無しで読込み
↓ サンプル無いの in変数は、InputStream
Tsvprocess process = new Tsvprocess(); process.readNoheader(in, StandardCharsets.UTF_8, (n, p)->{ // n=行番号(0始まり、インデックスとしてのカウント) p=1行の List<String> });
文字コード=UTF-8 で1行目はヘッダ行で、マップのキーとして読み込む
Tsvprocess process = new Tsvprocess(true); process.read(in, StandardCharsets.UTF_8, (n, m)->{ // n=行番号(1始まり、ヘッダを除くため) m=1行の Map<String, String> m.entrySet().stream().forEach(e->{ // e.getKey()=ヘッダキー e.getValue()=値 }); });