APIのテストに、curl コマンドばかり使っていたが、
Insomnia という便利なツールがあるんです。
https://docs.insomnia.rest/insomnia/get-started
いろんな開発者に出会ったけど、curl コマンドを使うことに変なプライドがあるように
見受けられる場面があって辟易していた。
APIのテストに、curl コマンドばかり使っていたが、
Insomnia という便利なツールがあるんです。
https://docs.insomnia.rest/insomnia/get-started
いろんな開発者に出会ったけど、curl コマンドを使うことに変なプライドがあるように
見受けられる場面があって辟易していた。
Windows環境では SourceTreeをアップデートしてもツールバーの破棄ボタン、
あるいは、変更ソースを右クリックして表示されるコンテキストメニューで
破棄は消えていないが、
Mac環境にインストールした SoureceTree ではこの「破棄」が存在しない。
GITコマンドで破棄の操作、git checkout の操作をした方が良いかも。
戻したい対象を指定する場合
git checkout {対象ソースのPATH}
全て戻したい場合
git checkout .
同様に戸惑った人はいるみたいで、下記にありました。隠れてるんですね。
https://qiita.com/Kobutorina_hato/items/9732db0e96fe0685d48f
昔作成して公開している CSVの読み書き、
GitHub - yipuran/yipuran-csv: Java CSV read and write
の中の
csvobject · yipuran/yipuran-csv Wiki · GitHub
から、CsvObject を継承して、TSV を総称型指定のクラスで読込む。
変更点は、
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();
読込みと同じ方法で対応できる。
oboe2uran.hatenablog.com
TSVの書き込みの場合の継承元は、yipuran-csv の Wiki - CSV書き込みを参照
いずれも、org.yipuran.csv4j.CSVWriter を使う時に、デリミタ措定を
カンマ区切りから、タブ区切りに変更することと、
1行分作成の Stream の join でタブ文字を指定するように
変更することである。
使い方は、yipuran-csv の Wiki - CSV書き込み と同じである。
TsvCreator
import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Serializable; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collection; import java.util.function.Supplier; import java.util.stream.Collectors; import org.yipuran.csv.BOMfunction; import org.yipuran.csv4j.CSVWriter; /** * TSV作成 interface */ @FunctionalInterface public interface TsvCreator extends Serializable{ /** * TSV出力行数分の Colleactionを返す Supplier を取得する. * @return Supplier<Collection<String[]>> */ public Supplier<Collection<String[]>> getSupplier(); /** * TSV出力実行. * @param out OutputStream * @param charName 文字セット名 */ default public void create(OutputStream out, String charName){ try(OutputStreamWriter writer = new OutputStreamWriter(out, charName)){ CSVWriter csvWriter = new CSVWriter(writer, '\t'); for(String[] s:getSupplier().get()){ for(int i=0;i < s.length;i++){ s[i] = s[i]==null ? "" : s[i]; } csvWriter.writeLine(s); } }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * ダブルクォート括りTSV出力実行. * @param out OutputStream * @param charName 文字セット名 */ default public void createWithDblQuot(OutputStream out, String charName){ String lineSeparator = System.getProperty("line.separator"); try(OutputStreamWriter writer = new OutputStreamWriter(out, charName)){ for(String[] sary:getSupplier().get()){ for(int i=0;i < sary.length;i++){ sary[i] = sary[i]==null ? "" : sary[i]; } writer.write(tsvline(sary)); writer.write(lineSeparator); } }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * BOM付きUTF-8 TSV出力実行 * @param out OutputStream */ default public void createBomUTF8(OutputStream out){ try(OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)){ BOMfunction.push(out); CSVWriter csvWriter = new CSVWriter(writer, '\t'); for(String[] sary:getSupplier().get()){ for(int i=0;i < sary.length;i++){ sary[i] = sary[i]==null ? "" : sary[i]; } csvWriter.writeLine(sary); } }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * BOM付きUTF-8ダブルクォート括り TSV出力実行 * @param out OutputStream */ default public void createBomUTF8WithDblQuot(OutputStream out){ String lineSeparator = System.getProperty("line.separator"); try(OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)){ BOMfunction.push(out); for(String[] sary:getSupplier().get()){ for(int i=0;i < sary.length;i++){ sary[i] = sary[i]==null ? "" : sary[i]; } writer.write(tsvline(sary)); writer.write(lineSeparator); } }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * ダブルクォート括り1行作成. * @param ary 1行生成する配列 * @return ダブルクォート括り1行 */ default public String tsvline(String[] ary){ return "\"" + Arrays.stream(ary).map(s->s.replaceAll("\"","\"\"")) .collect(Collectors.joining("\"\t\"")) + "\""; } }
TsvwriteArrayStream
String[] の Stream を指定する場合の為に
import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import org.yipuran.csv.BOMfunction; import org.yipuran.csv4j.CSVWriter; /** * 配列 Stream から生成 */ @FunctionalInterface public interface TsvwriteArrayStream{ /** * TSV出力行数分の String配列の Stream を返す Supplier を取得する. * @return Supplier<Stream<String[]>> */ Supplier<Stream<String[]>> getSupplier(); /** * TSV出力実行. * @param out OutputStream * @param charName 文字セット名 */ default public void create(OutputStream out, String charName){ try(OutputStreamWriter writer = new OutputStreamWriter(out, charName)){ CSVWriter csvWriter = new CSVWriter(writer, '\t'); getSupplier().get().map(s->{ for(int i=0;i < s.length;i++){ s[i] = s[i]==null ? "" : s[i]; } return s; }).forEach(t->{ try{ csvWriter.writeLine(t); }catch(IOException ex){ throw new RuntimeException(ex); } }); }catch(Exception ex){ throw new RuntimeException(ex.getMessage(), ex); } } /** * ダブルクォート括りTSV出力実行. * @param out OutputStream * @param charName 文字セット名 */ default public void createWithDblQuot(OutputStream out, String charName){ String lineSeparator = System.getProperty("line.separator"); try(OutputStreamWriter writer = new OutputStreamWriter(out, charName)){ getSupplier().get().map(s->{ for(int i=0;i < s.length;i++){ s[i] = s[i]==null ? "" : s[i]; } return s; }).forEach(t->{ try{ writer.write(tsvline(t)); writer.write(lineSeparator); }catch(IOException ex){ throw new RuntimeException(ex); } }); }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * BOM付きUTF-8 TSV出力実行 * @param out OutputStream */ default public void createBomUTF8(OutputStream out){ try(OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)){ BOMfunction.push(out); CSVWriter csvWriter = new CSVWriter(writer, '\t'); getSupplier().get().map(s->{ for(int i=0;i < s.length;i++){ s[i] = s[i]==null ? "" : s[i]; } return s; }).forEach(t->{ try{ csvWriter.writeLine(t); }catch(IOException ex){ throw new RuntimeException(ex); } }); }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * BOM付きUTF-8ダブルクォート括り TSV出力実行 * @param out OutputStream */ default public void createBomUTF8WithDblQuot(OutputStream out){ String lineSeparator = System.getProperty("line.separator"); try(OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)){ BOMfunction.push(out); getSupplier().get().map(s->{ for(int i=0;i < s.length;i++){ s[i] = s[i]==null ? "" : s[i]; } return s; }).forEach(t->{ try{ writer.write(tsvline(t)); writer.write(lineSeparator); }catch(IOException ex){ throw new RuntimeException(ex); } }); }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * ダブルクォート括り1行作成. * @param ary 1行生成する配列 * @return ダブルクォート括り1行 */ default public String tsvline(String[] ary){ return "\"" + Arrays.stream(ary).map(s->s.replaceAll("\"","\"\"")) .collect(Collectors.joining("\"\t\"")) + "\""; } }
TsvwriteListStream
List<String> の Stream から生成
import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import org.yipuran.csv.BOMfunction; import org.yipuran.csv4j.CSVWriter; /** * List<String> の Stream から生成 */ @FunctionalInterface public interface TsvwriteListStream{ Supplier<Stream<List<String>>> getSupplier(); /** * TSV出力実行. * @param out OutputStream * @param charName 文字セット名 */ default public void create(OutputStream out, String charName){ try(OutputStreamWriter writer = new OutputStreamWriter(out, charName)){ CSVWriter csvWriter = new CSVWriter(writer, '\t'); getSupplier().get().map(list->list.stream().map(s->s==null ? "" : s) .collect(Collectors.toList())) .forEach(t->{ try{ csvWriter.writeLine(t); }catch(IOException ex){ throw new RuntimeException(ex); } }); }catch(Exception ex){ throw new RuntimeException(ex.getMessage(), ex); } } /** * ダブルクォート括りTSV出力実行. * @param out OutputStream * @param charName 文字セット名 */ default public void createWithDblQuot(OutputStream out, String charName){ String lineSeparator = System.getProperty("line.separator"); try(OutputStreamWriter writer = new OutputStreamWriter(out, charName)){ getSupplier().get().map(list->list.stream().map(s->s==null ? "" : s) .collect(Collectors.toList())) .forEach(t->{ try{ writer.write(tsvline(t)); writer.write(lineSeparator); }catch(IOException ex){ throw new RuntimeException(ex); } }); }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * BOM付きUTF-8 TSV出力実行 * @param out OutputStream */ default public void createBomUTF8(OutputStream out){ try(OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)){ BOMfunction.push(out); CSVWriter csvWriter = new CSVWriter(writer, '\t'); getSupplier().get().map(list->list.stream().map(s->s==null ? "" : s) .collect(Collectors.toList())) .forEach(t->{ try{ csvWriter.writeLine(t); }catch(IOException ex){ throw new RuntimeException(ex); } }); }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * BOM付きUTF-8ダブルクォート括り TSV出力実行 * @param out OutputStream */ default public void createBomUTF8WithDblQuot(OutputStream out){ String lineSeparator = System.getProperty("line.separator"); try(OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8)){ BOMfunction.push(out); getSupplier().get().map(list->list.stream().map(s->s==null ? "" : s) .collect(Collectors.toList())) .forEach(t->{ try{ writer.write(tsvline(t)); writer.write(lineSeparator); }catch(IOException ex){ throw new RuntimeException(ex); } }); }catch(Exception e){ throw new RuntimeException(e.getMessage(), e); } } /** * Collection→ダブルクォート括り1行作成. * @param list 1行生成する文字列 List * @return ダブルクォート括り1行 */ default public String tsvline(List<String> list){ return "\"" + list.stream().map(s->s.replaceAll("\"","\"\"")) .collect(Collectors.joining("\"\t\"")) + "\""; } }
昔作成して公開している CSVの読み書き、
GitHub - yipuran/yipuran-csv: Java CSV read and write
これは、TSV ファイルで使用することを目的にしていなかった。
長いこと開発をしていて、なかなかTSVファイルを対象にすることが少なかった。
この yipuran-csv の中の、Csvprocess と同じ機能で、TSV読込みは、継承をすることで
次のように用意できる。
Csvprocess の説明は、→ こちらのWiki
継承して、TSV用に用意するポイントは、
後は、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()=値 }); });
うっかり shallow copy のまま操作してしまうのを注意したい。
サンプル
{ "A" : "a", "B" : { "B01" : "b01-01234", "B02" : { "detail" : "test_sample", "name" : { "type" : "merge", "len" : 12 } } }, "C" : [ 100, 160, 300 ] }
この JSONを表すString jsonstr から生成する JsonNode を以下のようにすると
shallow copy になってしまう。
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(jsonstr);
JsonNode node2 = node; ((ObjectNode)(node2.path("B").path("B02"))).put("detail", "test_sample"); ((ObjectNode)(node2.path("B").path("B02"))).replace("name", mapper.createObjectNode() .put("type", "merge").put("len", 12)); ((ArrayNode)(node2.path("C"))).set(1, 160);
node2 を変更しているつもりが、node を変更していることになる。
ディープコピー(deepCopy)を使うようにして元の JsonNode が変更されないようにする
JsonNode node2 = node.deepCopy(); ((ObjectNode)(node2.path("B").path("B02"))).put("detail", "test_sample"); ((ObjectNode)(node2.path("B").path("B02"))).replace("name", mapper.createObjectNode() .put("type", "merge").put("len", 12)); ((ArrayNode)(node2.path("C"))).set(1, 160);
node2 は、
{ "A" : "a", "B" : { "B01" : "b01-01234", "B02" : { "detail" : "test_sample", "name" : { "type" : "merge", "len" : 12 } } }, "C" : [ 100, 160, 300 ] }