Java解析多个具有不同头和模型对象的CSV文件的最佳设计
我有几个CSV文件需要解析。稍后用于MYSQL中的Insert。我已经编写了一个解析器,但我希望尽可能避免代码重复 我已经想到我应该使用一个抽象类,或者一个工厂,但是我真的不能确定设计这个的最佳方法 这是我的解析器:Java解析多个具有不同头和模型对象的CSV文件的最佳设计,java,parsing,design-patterns,abstract-class,factory,Java,Parsing,Design Patterns,Abstract Class,Factory,我有几个CSV文件需要解析。稍后用于MYSQL中的Insert。我已经编写了一个解析器,但我希望尽可能避免代码重复 我已经想到我应该使用一个抽象类,或者一个工厂,但是我真的不能确定设计这个的最佳方法 这是我的解析器: public class LocusAliasCsvParser { private static final String[] FILE_HEADER_MAPPING = {"id", "locusID", "organismid", "variable", "alias"};
public class LocusAliasCsvParser {
private static final String[] FILE_HEADER_MAPPING = {"id", "locusID", "organismid", "variable", "alias"};
private static final String ID = "id";
private static final String LOCUS_ID = "locusID";
private static final String ORGANISM_ID = "organismid";
private static final String VARIABLE = "variable";
private static final String ALIAS = "alias";
public static List<AliasLocus> readCsvFile(String fileName) {
FileReader fileReader = null;
CSVParser csvFileParser = null;
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER_MAPPING);
List<AliasLocus> aliases = new ArrayList();
try {
fileReader = new FileReader(fileName);
csvFileParser = new CSVParser(fileReader, csvFileFormat);
//Get a list of CSV file records
List csvRecords = csvFileParser.getRecords();
//Read the CSV file. Header is ignored (i == 1)
for (int i = 1; i < csvRecords.size(); i++) {
CSVRecord record = (CSVRecord) csvRecords.get(i);
AliasLocus aliasLocus = new AliasLocus(Integer.parseInt(record.get(ID)),
record.get(LOCUS_ID),
record.get(ORGANISM_ID),
record.get(VARIABLE),
record.get(ALIAS));
aliases.add(aliasLocus);
}
} catch (Exception e) {
System.out.println("Error in CsvFileReader !!!");
e.printStackTrace();
} finally {
try {
fileReader.close();
csvFileParser.close();
} catch (IOException e) {
System.out.println("Error while closing fileReader/csvFileParser !!!");
e.printStackTrace();
}
}
return aliases;
}
以及:
公共静态列表readCsvFile(字符串文件名){
AliasLocale AliasLocale=新的AliasLocale(Integer.parseInt(record.get(ID)),
记录。获取(轨迹ID),
记录。获取(有机体ID),
record.get(变量),
record.get(别名));
是否有人能建议使用最佳的设计模式或结构以减少代码重复
谢谢这是我非常严格的解决方案 声明从CSVRecord到每个所需实体的转换器:
class AliasLocusMapper {
public static final String[] FILE_HEADER_MAPPING = {"id", "locusID", "organismid", "variable", "alias"};
private static final String ID = "id";
private static final String LOCUS_ID = "locusID";
private static final String ORGANISM_ID = "organismid";
private static final String VARIABLE = "variable";
private static final String ALIAS = "alias";
public static AliasLocus mapRecord(CSVRecord record) {
return new AliasLocus(Integer.parseInt(record.get(ID)),
record.get(LOCUS_ID),
record.get(ORGANISM_ID),
record.get(VARIABLE),
record.get(ALIAS));
}
}
class ProductMapper { // Product is an example class
public static final String[] FILE_HEADER_MAPPING = {"id", "title", "price"};
private static final String ID = "id";
private static final String TITLE = "title";
private static final String PRICE = "price";
public static Product mapRecord(CSVRecord record) {
return new Product(Integer.parseInt(record.get(ID)),
record.get(TITLE),
record.get(PRICE));
}
}
然后使解析器更通用
public class AbstractCsvParser {
public <T> List<T> readCsvFile(String fileName, String[] headers, Function<CSVRecord, T> mapper) {
FileReader fileReader = null;
CSVParser csvFileParser = null;
CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(headers);
List<T> entities = new ArrayList<>();
try {
fileReader = new FileReader(fileName);
csvFileParser = new CSVParser(fileReader, csvFileFormat);
//Get a list of CSV file records
List csvRecords = csvFileParser.getRecords();
//Read the CSV file. Header is ignored (i == 1)
for (int i = 1; i < csvRecords.size(); i++) {
CSVRecord record = (CSVRecord) csvRecords.get(i);
T result = mapper.apply(record); // transform to desired enitity
entities.add(result);
}
} catch (Exception e) {
// omitted
}
return entities;
}
}
公共类抽象CSVParser{
公共列表readCsvFile(字符串文件名、字符串[]头、函数映射器){
FileReader FileReader=null;
CSVParser csvFileParser=null;
CSVFormat csvFileFormat=CSVFormat.DEFAULT.withHeader(headers);
列表实体=新的ArrayList();
试一试{
fileReader=新的fileReader(文件名);
csvFileParser=新的CSVParser(文件阅读器,csvFileFormat);
//获取CSV文件记录的列表
List csvRecords=csvFileParser.getRecords();
//读取CSV文件。忽略标头(i==1)
对于(int i=1;i
然后按以下方式使用
AbstractCsvParser parser = new AbstractCsvParser();
List<AliasLocus> aliases = parser.readCsvFile(
"aliases.csv",
AliasLocusMapper.FILE_HEADER_MAPPING,
AliasLocusMapper::mapRecord);
List<Product> products = parser.readCsvFile(
"products.csv",
ProductMapper.FILE_HEADER_MAPPING,
ProductMapper::mapRecord);
AbstractCsvParser parser=新的AbstractCsvParser();
列表别名=parser.readCsvFile(
“别名.csv”,
AliasLocusMapper.FILE_头_映射,
AliasLoomsMapper::mapRecord);
列表产品=parser.readCsvFile(
“products.csv”,
ProductMapper.FILE\u头\u映射,
ProductMapper::mapRecord);
您应该使用接口分离不同的关注点,并实现读取csv文件的模板方法
让我们分6个步骤设置一个简单的框架
public interface CsvMetadataSource {
public CsvMetadata getCsvMetadata();
}
CsvMetadata
是将该逻辑放入的好地方
public class CsvMetadata {
private List<String> columns;
public CsvMetadata(List<String> columns) {
this.columns = columns;
}
public Map<String, String> parseLine(String line) {
// simple implementation
String[] values = line.split(",");
Map<String, String> record = new HashMap<>();
for (int i = 0; i < columns.size(); i++) {
String column = columns.get(i);
String value = null;
if (i < values.length) {
value = values[i];
}
record.put(column, value);
}
return record;
}
}
public class Main {
public static void main(String[] args) throws IOException {
InputStream csvInputStream = Main.class.getResourceAsStream("example.csv");
InputStreamReader inputStreamReader = new InputStreamReader(csvInputStream);
CsvReader csvReader = new CsvReader();
List<User> users = csvReader.readAll(inputStreamReader, new UserCsvRecordMapper());
for (User user : users) {
System.out.println(user);
}
}
}
public class CsvMetadata {
private List<String> columns;
public CsvMetadata(List<String> columns) {
this.columns = columns;
}
public Map<String, String> parseLine(String line) {
// simple implementation
String[] values = line.split(",");
Map<String, String> record = new HashMap<>();
for (int i = 0; i < columns.size(); i++) {
String column = columns.get(i);
String value = null;
if (i < values.length) {
value = values[i];
}
record.put(column, value);
}
return record;
}
}
public interface CsvRecordMapper<T> {
public T map(Map<String, String> csvRecord, int lineNumber);
}
public interface CsvObjectCallback<T> {
public void process(T object);
}
public class CsvReader {
private CsvMetadataSource csvMetadataSource = null;
public CsvReader() {
}
public CsvReader(CsvMetadataSource csvMetadataSource) {
this.csvMetadataSource = csvMetadataSource;
}
public <T> List<T> readAll(Reader csvInputReader, CsvRecordMapper<T> csvLineMapper) throws IOException {
CollectCsvObjectCallback<T> collectCsvObjectCallback = new CollectCsvObjectCallback<>();
read(csvInputReader, csvLineMapper, collectCsvObjectCallback);
return collectCsvObjectCallback.getObjects();
}
public <T> void read(Reader csvInputReader, CsvRecordMapper<T> csvLineMapper,
CsvObjectCallback<T> csvObjectCallback) throws IOException {
try (BufferedReader lineReader = new BufferedReader(csvInputReader);) {
CsvMetadataSource effectiveCsvMetadataSource = getCsvMetadataSource(lineReader);
read(csvLineMapper, csvObjectCallback, lineReader, effectiveCsvMetadataSource);
}
}
private CsvMetadataSource getCsvMetadataSource(BufferedReader lineReader) throws IOException {
CsvMetadataSource effectiveCsvMetadataSource = csvMetadataSource;
if (effectiveCsvMetadataSource == null) {
String headerLine = lineReader.readLine();
effectiveCsvMetadataSource = new RowBasedCsvMetadataSource(headerLine);
}
return effectiveCsvMetadataSource;
}
private <T> void read(CsvRecordMapper<T> csvLineMapper, CsvObjectCallback<T> csvObjectCallback,
BufferedReader lineReader, CsvMetadataSource effectiveCsvMetadataSource) throws IOException {
CsvMetadata effectiveCsvMetadata = effectiveCsvMetadataSource.getCsvMetadata();
if (effectiveCsvMetadata != null) {
String line;
int csvRecordNumber = 0;
while ((line = lineReader.readLine()) != null) {
Map<String, String> csvRecordValues = effectiveCsvMetadata.parseLine(line);
T object = csvLineMapper.map(csvRecordValues, csvRecordNumber++);
csvObjectCallback.process(object);
}
}
}
}
class RowBasedCsvMetadataSource implements CsvMetadataSource {
private String row;
public RowBasedCsvMetadataSource(String row) {
this.row = row;
}
@Override
public CsvMetadata getCsvMetadata() {
String[] columns = row.split(",");
return new CsvMetadata(Arrays.asList(columns));
}
}
class CollectCsvObjectCallback<T> implements CsvObjectCallback<T> {
private List<T> objects = new ArrayList<>();
@Override
public void process(T object) {
objects.add(object);
}
public List<T> getObjects() {
return objects;
}
}
public class UserCsvRecordMapper implements CsvRecordMapper<User> {
public User map(Map<String, String> csvRecord, int lineNumber) {
String firstname = csvRecord.get("FIRST NAME");
String lastname = csvRecord.get("LAST NAME");
String username = csvRecord.get("USERNAME");
String email = csvRecord.get("EMAIL ADDRESS");
return new User(firstname, lastname, username, email);
}
}
public class User {
private String firstname;
private String lastname;
private String username;
private String email;
public User(String firstname, String lastname, String username, String email) {
this.firstname = firstname;
this.lastname = lastname;
this.username = username;
this.email = email;
}
public String getFirstname() {
return firstname;
}
public String getLastname() {
return lastname;
}
public String getUsername() {
return username;
}
public String getEmail() {
return email;
}
@Override
public String toString() {
return "User [firstname=" + firstname + ", lastname=" + lastname + ", username=" + username + ", email=" + email
+ "]";
}
}
FIRST NAME,LAST NAME,USERNAME,PASSWORD,EMAIL ADDRESS,PHONE NUMBER,PASSPORT,GROUPS,USERCODE,TITLE,ADDRESS 1 ,ADDRESS 2,CITY,STATE,ZIP
Frank,Riley,friley,changeme,friley@kanab.org,123-456-7890,3,"1,3",1040,Teacher,328 Innovation,Suite # 200 ,state college,PA,16803
Steve,Brannigan,sbrannigan,changeme,sbrannigan@kanab.org,123-456-7890,3,1,1041,Teacher,328 Innovation,Suite # 200 ,state college,PA,16803
Marie,Ambrose,mambrose,changeme,mambrose@kanab.org,123-456-7890,3,1,1042,Teacher,328 Innovation,Suite # 200 ,state college,PA,16803
public class Main {
public static void main(String[] args) throws IOException {
InputStream csvInputStream = Main.class.getResourceAsStream("example.csv");
InputStreamReader inputStreamReader = new InputStreamReader(csvInputStream);
CsvReader csvReader = new CsvReader();
List<User> users = csvReader.readAll(inputStreamReader, new UserCsvRecordMapper());
for (User user : users) {
System.out.println(user);
}
}
}
User [firstname=Frank, lastname=Riley, username=friley, email=friley@kanab.org]
User [firstname=Steve, lastname=Brannigan, username=sbrannigan, email=sbrannigan@kanab.org]
User [firstname=Marie, lastname=Ambrose, username=mambrose, email=mambrose@kanab.org]