昔作成して公開している 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;
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=ブランク、",,"
public void setBlanknull(boolean blankIsNull) {
this.blankIsNull = blankIsNull;
}
総称型指定TSV読込み実行.
@param inReader
@param biconsumer
@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
@return
@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
@param converter
@param biconsumer
@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
@param converter
@return
@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)->{
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();