次の列を持つCSVファイルがあります:id
、fname
、telephone
、lname
、address
。
Person
、id
、fname
のデータメンバーを持つlname
クラスがあります。これらの列のみをCSVファイルのPerson
オブジェクトにマップし、telephone
列とaddress
列を破棄したいです。これどうやってするの?ソリューションは、将来さらに列が追加されるにつれて拡張する必要があります。列の位置に関係なく動作するはずです。
理想的なソリューションでは、ユーザーは読み取る列のみを指定し、動作するはずです。
HeaderColumnNameTranslateMappingStrategy を使用できます。 CSVに次の列があると仮定しましょう:簡単にするために、Id
、Fname
、Telephone
、Lname
、Address
です。
CsvToBean<Person> csvToBean = new CsvToBean<Person>();
Map<String, String> columnMapping = new HashMap<String, String>();
columnMapping.put("Id", "id");
columnMapping.put("Fname", "fname");
columnMapping.put("Lname", "lname");
HeaderColumnNameTranslateMappingStrategy<Person> strategy = new HeaderColumnNameTranslateMappingStrategy<Person>();
strategy.setType(Person.class);
strategy.setColumnMapping(columnMapping);
List<Person> list = null;
CSVReader reader = new CSVReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream("test.csv")));
list = csvToBean.parse(strategy, reader);
ColumnMappingは、列をPerson
オブジェクトにマップします。
OpenCSVの最近のバージョンでは、メソッドparse(X, Y)
が非推奨になりました。代わりにBeanBuilderを使用することを推奨しているため、トップの回答は古くなっています。
try {
CsvToBeanBuilder<PersonCSV> beanBuilder = new CsvToBeanBuilder<>(new InputStreamReader(new FileInputStream("your.csv")));
beanBuilder.withType(PersonCSV.class);
// build methods returns a list of Beans
beanBuilder.build().parse().forEach(e -> log.error(e.toString()));
} catch (FileNotFoundException e) {
log.error(e.getMessage(), e);
}
このメソッドを使用すると、コードをクリーンアップし、MappingStrategyを削除できます(スパゲッティが好きな場合は引き続き使用できます)。そのため、次のようにCSVクラスに注釈を付けることができます。
@CsvDate("dd/MM/yyyy hh:mm:ss")
@CsvBindByName(column = "Time Born", required = true)
private Date birthDate;
Opencsvについて話すことはできませんが、これは Super CSV を使用して簡単に達成できます。2つの異なる readers をサポートします partial reading (列を無視)、およびJavabeanへの読み込み。 CsvDozerBeanReader
は ディープおよびインデックスベースのマッピング にも対応しているため、ネストされたフィールドにマッピングできます。
私たち(Super CSVチーム)は、バージョン2.0.0をリリースしました。これは、Maven centralまたはSourceForgeから入手できます。
更新
以下に、opencsvの代わりにSuper CSVを使用する(作成したGitHubプロジェクトのテストに基づく)例があります。 CSV設定では、サンプルCSVファイルが無効であるため、surroundingSpacesNeedQuotes
フラグを有効にする必要があります(フィールド間にスペースがあります-スペースはCSVのデータの一部と見なされます)。
ICsvBeanReader beanReader = null;
try {
beanReader = new CsvBeanReader(
new InputStreamReader(
ClassLoader.getSystemResourceAsStream("test.csv")),
new CsvPreference.Builder(CsvPreference.STANDARD_PREFERENCE)
.surroundingSpacesNeedQuotes(true).build());
List<String> columnsToMap = Arrays.asList("fname", "telephone", "id");
// read the CSV header (and set any unwanted columns to null)
String[] header = beanReader.getHeader(true);
for (int i = 0; i < header.length; i++) {
if (!columnsToMap.contains(header[i])) {
header[i] = null;
}
}
Person person;
while ((person = beanReader.read(Person.class, header)) != null) {
System.out.println(person);
}
} finally {
beanReader.close();
}
niVocity-parsers を使用して完了です。入力CSVで列がどのように編成されているかは関係ありません。必要なものだけが解析されます。
書き込む場合、クラスにある列は正しい列に書き込まれ、他の列は空になります。
以下にいくつかの例を示すクラスを示します。
class TestBean {
// if the value parsed in the quantity column is "?" or "-", it will be replaced by null.
@NullString(nulls = { "?", "-" })
// if a value resolves to null, it will be converted to the String "0".
@Parsed(defaultNullRead = "0")
private Integer quantity; // The attribute type defines which conversion will be executed when processing the value.
@Trim
@LowerCase
// the value for the comments attribute is in the column at index 4 (0 is the first column, so this means fifth column in the file)
@Parsed(index = 4)
private String comments;
// you can also explicitly give the name of a column in the file.
@Parsed(field = "amount")
private BigDecimal amount;
@Trim
@LowerCase
// values "no", "n" and "null" will be converted to false; values "yes" and "y" will be converted to true
@BooleanString(falseStrings = { "no", "n", "null" }, trueStrings = { "yes", "y" })
@Parsed
private Boolean pending;
}
TestBean
のリストを取得する方法は次のとおりです。
BeanListProcessor<TestBean> rowProcessor = new BeanListProcessor<TestBean>(TestBean.class);
CsvParserSettings parserSettings = new CsvParserSettings();
parserSettings.setRowProcessor(rowProcessor);
parserSettings.setHeaderExtractionEnabled(true);
CsvParser parser = new CsvParser(parserSettings);
parser.parse(getReader("/examples/bean_test.csv"));
List<TestBean> beans = rowProcessor.getBeans();
開示:私はこのライブラリの著者です。オープンソースで無料です(Apache V2.0ライセンス)。
OpenCSVを使用してPOJOへのマッピングを一般的に行う良い方法は次のとおりです。
protected <T> List<T> mapToCSV(String csvContent, Class<T> mapToClass) {
CsvToBean<T> csvToBean = new CsvToBean<T>();
Map<String, String> columnMapping = new HashMap<>();
Arrays.stream(mapToClass.getDeclaredFields()).forEach(field -> {
columnMapping.put(field.getName(), field.getName());
});
HeaderColumnNameTranslateMappingStrategy<T> strategy = new HeaderColumnNameTranslateMappingStrategy<T>();
strategy.setType(mapToClass);
strategy.setColumnMapping(columnMapping);
CSVReader reader = new CSVReader(new StringReader(csvContent));
return csvToBean.parse(strategy, reader);
}
public static class MyPojo {
private String foo, bar;
public void setFoo(String foo) {
this.foo = foo;
}
public void setBar(String bar) {
this.bar = bar;
}
}
次に、テストから次を使用できます。
List<MyPojo> list = mapToCSV(csvContent, MyPojo.class);
jcvsdaoの使用例
サンプルユーザーCSVファイル
Username, Email, Registration Date, Age, Premium User
Jimmy, [email protected], 04-05-2016, 15, Yes, M
Bob, [email protected], 15-01-2012, 32, No, M
Alice, [email protected], 22-09-2011, 24, No, F
Mike, [email protected], 11-03-2012, 18, Yes, M
Helen, [email protected], 02-12-2013, 22, Yes, F
Tom, [email protected], 08-11-2015, 45, No, M
CsvDaoを作成する
CSVDaoFactory factory = new CSVDaoFactory("/csv-config.xml");
CSVDao dao = new CSVDao(factory);
List<UserDetail> users = dao.find(UserDetail.class);
csv-config.xml
<CSVConfig>
<mappingFiles fileType="resource">
<mappingFile>/example01/mapping/UserDetail.csv.xml</mappingFile>
</mappingFiles>
</CSVConfig>
UserDetail.csv.xml
<CSVMapping className="org.jcsvdao.examples.example01.model.UserDetail" csvFile="csv-examples/example01/users.txt" delimiter="," ignoreFirstLine="true">
<matchAll/>
<properties>
<property index="0" property="username" primaryKey="true"/>
<property index="1" property="email"/>
<property index="2" property="registrationDate" converter="myDateConverter"/>
<property index="3" property="age"/>
<property index="4" property="premiumUser" converter="yesNoConverter"/>
<property index="5" property="gender" converter="myGenderConverter"/>
</properties>
<converters>
<dateConverter converterName="myDateConverter" format="dd-MM-yyyy"/>
<booleanConverter converterName="yesNoConverter" positive="Yes" negative="No"/>
<customConverter converterName="myGenderConverter" converterClass="org.jcsvdao.examples.example01.converter.GenderCustomerConverter"/>
</converters>
</CSVMapping>
https://github.com/arnaudroger/SimpleFlatMapper 0.9.4の最新バージョンにCsvMapperが追加されました。ヘッダーを使用してプロパティ名と照合します。ヘッダーがない場合は、ビルダーで列名を指定できます。コンストラクター、セッター、およびフィールド注入をサポートします。 InputStreamまたはReaderから読み取ります。
public class MyParser {
private final CsvMapper<MyObject> mapper =
CsvMapperFactory.newInstance().newMapper(MyObject.class);
public void writeAllObjectToLambda(Writer writer, InputStream is) throws IOException {
mapper.forEach(is, (o) -> writer.append(o.toString()).append("\n"));
}
}
Jcsvdaoをご覧ください https://github.com/eric-mckinley/jcsvdao/ は、休止状態のスタイルマッピングファイルを使用し、1to1および1toManyの関係を処理できます。柔軟なマッチング戦略があるため、csvファイルを所有していない場合に適しています。
この問題に取り組むための柔軟なソリューションを実装しました。使い方は非常に簡単で、以下の私のgithubで例のコードを入手できます。