Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java解析多个具有不同头和模型对象的CSV文件的最佳设计_Java_Parsing_Design Patterns_Abstract Class_Factory - Fatal编程技术网

Java解析多个具有不同头和模型对象的CSV文件的最佳设计

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"};

我有几个CSV文件需要解析。稍后用于MYSQL中的Insert。我已经编写了一个解析器,但我希望尽可能避免代码重复

我已经想到我应该使用一个抽象类,或者一个工厂,但是我真的不能确定设计这个的最佳方法

这是我的解析器:

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个步骤设置一个简单的框架

  • 您需要一个知道如何获取csv结构的类

    public interface CsvMetadataSource {
         public CsvMetadata getCsvMetadata();
    }
    
  • 您需要一个可以解析csv行的类。1中的
    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;
        }
    
    }
    
  • 从客户的角度来看,它很容易使用

    CSV

    和一个简单的主类

    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]