昔作成して公開している CSVの読み書き、
GitHub - yipuran/yipuran-csv: Java CSV read and write
の中の
csvobject · yipuran/yipuran-csv Wiki · GitHub
から、CsvObject を継承して、TSV を総称型指定のクラスで読込む。
変更点は、
- org.yipuran.csv4j.CSVReader からデリミタ指定をカンマ区切りからタブ文字に変えるだけ
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.nio.charset.Charset; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.stream.Stream; import org.yipuran.csv.BOMfunction; import org.yipuran.csv.CsvObject; import org.yipuran.csv4j.CSVReader; import org.yipuran.csv4j.ProcessingException; /** * TSV を総称型指定のクラスで読込み */ public class TsvObject<T> extends CsvObject<T>{ private static final char DELIMITER = '\t'; private boolean blankIsNull = false; private Class<T> cls; private List<Class<?>> typelist; private List<Method> methodlist; private DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_LOCAL_DATE;// DateTimeFormatter.ofPattern("yyyy-MM-dd"); private DateTimeFormatter localdatetimeFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME; private DateTimeFormatter timeFormatter = DateTimeFormatter.ISO_LOCAL_TIME; private Function<String, Boolean> booleanReader = s -> Boolean.parseBoolean(s.toLowerCase()); /** * コンストラクタ. * @param t 可変長引数、指定しても使用はされない */ @SuppressWarnings("unchecked") public TsvObject(T...t) { cls = (Class<T>)t.getClass().getComponentType(); } /** * ブランク→null指定. * @param true=ブランク、",," は、null として読み込む。 */ public void setBlanknull(boolean blankIsNull) { this.blankIsNull = blankIsNull; } /** * 総称型指定TSV読込み実行. * @param inReader InputStreamReader * @param biconsumer コンテンツ行BiConsumer、TSV行読込みカウント(1始まり)と総称型Tのオブジェクト * @throws IOException * @throws ProcessingException */ @Override public void read(InputStreamReader inReader, BiConsumer<Integer, T> biconsumer) throws IOException, ProcessingException{ CSVReader reader = new CSVReader(new BufferedReader(inReader), Charset.forName(inReader.getEncoding()), DELIMITER, getComment(), blankIsNull); try{ typelist = new ArrayList<>(); methodlist = new ArrayList<>(); 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)); } for(String f:fields){ try{ Class<?> c = cls.getDeclaredField(f).getType(); Method m = cls.getDeclaredMethod("set" + f.substring(0, 1).toUpperCase() + f.substring(1), c); typelist.add(c); methodlist.add(m); }catch(NoSuchFieldException | NoSuchMethodException e){ typelist.add(null); methodlist.add(null); } } }else{ T t = cls.getConstructor().newInstance(); int i=0; for(String f:fields){ Method m = methodlist.get(i); if (m != null){ setValue(m, t, i, f); } i++; } biconsumer.accept(lineCount, t); } }catch(Exception e){ throw new ProcessingException(e, reader.getLineNumber()); } lineCount++; } }finally{ reader.close(); } } /** * 総称型指定TSV読込み結果Stream生成. * @param inReader InputStreamReader * @return 総称型 T のStream * @throws IOException * @throws ProcessingException */ @Override public Stream<T> read(InputStreamReader inReader) throws IOException, ProcessingException{ Stream.Builder<T> builder = Stream.builder(); CSVReader reader = new CSVReader(new BufferedReader(inReader), Charset.forName(inReader.getEncoding()), DELIMITER, getComment(), blankIsNull); try{ typelist = new ArrayList<>(); methodlist = new ArrayList<>(); 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)); } for(String f:fields){ try{ Class<?> c = cls.getDeclaredField(f).getType(); Method m = cls.getDeclaredMethod("set" + f.substring(0, 1).toUpperCase() + f.substring(1), c); typelist.add(c); methodlist.add(m); }catch(NoSuchFieldException | NoSuchMethodException e){ typelist.add(null); methodlist.add(null); } } }else{ T t = cls.getConstructor().newInstance(); int i=0; for(String f:fields){ Method m = methodlist.get(i); if (m != null){ setValue(m, t, i, f); } i++; } builder.add(t); } }catch(Exception e){ throw new ProcessingException(e, reader.getLineNumber()); } lineCount++; } }finally{ reader.close(); } return builder.build(); } /** * 総称型指定TSV読込み実行(コンバーター指定). * @param inReader InputStreamReader * @param converter TSV1行分の文字列リストから、総称型Tを生成取得するコンバーター * @param biconsumer コンテンツ行BiConsumer、TSV行読込みカウント(1始まり)と総称型Tのオブジェクト * @throws IOException * @throws ProcessingException */ @Override public void read(InputStreamReader inReader, Function<List<String>, T> converter, BiConsumer<Integer, T> biconsumer) throws IOException, ProcessingException{ CSVReader reader = new CSVReader(new BufferedReader(inReader), Charset.forName(inReader.getEncoding()), DELIMITER, getComment(), blankIsNull); try{ methodlist = new ArrayList<>(); int lineCount = 0; while(true){ try{ List<String> fields = reader.readLine(); if (fields.size()==0) break; if (!isHasHeader() || lineCount > 0){ biconsumer.accept(lineCount, converter.apply(fields)); } }catch(Exception e){ throw new ProcessingException(e, reader.getLineNumber()); } lineCount++; } }finally{ reader.close(); } } /** * 総称型指定TSV読込み結果Stream生成(コンバーター指定). * @param inReader InputStreamReader * @param converter TSV1行分の文字列リストから、総称型Tを生成取得するコンバーター * @return 総称型 T のStream * @throws IOException * @throws ProcessingException */ @Override public Stream<T> read(InputStreamReader inReader, Function<List<String>, T> converter) throws IOException, ProcessingException{ Stream.Builder<T> builder = Stream.builder(); 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){ builder.add(converter.apply(fields)); } }catch(Exception e){ throw new ProcessingException(e, reader.getLineNumber()); } lineCount++; } }finally{ reader.close(); } return builder.build(); } private void setValue(Method m, Object obj, int n, String str) throws NoSuchMethodException, SecurityException , IllegalAccessException, IllegalArgumentException { try{ if (typelist.get(n).isPrimitive()) { if (blankIsNull && str==null) return; Class<?> c = typelist.get(n); if (c.equals(int.class)) { m.invoke(obj, Integer.parseInt(str)); }else if(c.equals(long.class)) { m.invoke(obj, Long.parseLong(str)); }else if(c.equals(double.class)) { m.invoke(obj, Double.parseDouble(str)); }else if(c.equals(short.class)) { m.invoke(obj, Short.parseShort(str)); }else if(c.equals(float.class)) { m.invoke(obj, Float.parseFloat(str)); }else if(c.equals(boolean.class)) { m.invoke(obj, booleanReader.apply(str)); } }else{ if (typelist.get(n).equals(String.class)) { m.invoke(obj, str); }else if(typelist.get(n).equals(Boolean.class)) { m.invoke(obj, booleanReader.apply(str)); }else if(typelist.get(n).equals(LocalDate.class)) { m.invoke(obj, LocalDate.parse(str, dateFormatter)); }else if(typelist.get(n).equals(LocalDateTime.class)) { m.invoke(obj, LocalDateTime.parse(str, localdatetimeFormatter)); }else if(typelist.get(n).equals(LocalTime.class)) { m.invoke(obj, LocalTime.parse(str, timeFormatter)); }else{ Method getter = typelist.get(n).getDeclaredMethod("valueOf", String.class); m.invoke(obj, getter.invoke(null, str)); } } }catch(InvocationTargetException e){ } } }
(使用例)
TSVの1行を任意クラスFoo として読み込む。ただしヘッダ1行目がフィールド名である。
TsvObject<Foo> co = new TsvObject<>(); co.setBlanknull(true); co.read(new InputStreamReader(in, StandardCharsets.UTF_8), (i, f)->{ // i=読み出し行番号 1 始まり、 // f=Fooインスタンス(1行 → Foo 変換結果) System.out.println("["+i+"]# "+f.toString()); }); in.close();
TsvObject<Foo> co = new TsvObject<>(); co.setBlanknull(true); co.read(new InputStreamReader(in, StandardCharsets.UTF_8)).forEach(f->{ System.out.println(f.toString()); }); in.close();