【问题标题】:Parsing several csv files using Spring Batch使用 Spring Batch 解析多个 csv 文件
【发布时间】:2015-11-18 10:30:07
【问题描述】:

我需要解析给定文件夹中的几个 csv 文件。由于每个 csv 都有不同的列,因此每个 csv 在 DB 中都有单独的表。我需要知道

  • spring batch 是否提供任何机制来扫描给定文件夹,然后我可以将这些文件一个一个传递给阅读器。
  • 当我试图使读取器/写入器通用时,是否可以只获取每个 csv 的列标题,基于我正在尝试构建标记器以及插入查询。

代码示例

public ItemReader<Gdp> reader1() {
    FlatFileItemReader<Gdp> reader1 = new FlatFileItemReader<Gdp>();
    reader1.setResource(new ClassPathResource("datagdp.csv"));
    reader1.setLinesToSkip(1);
    reader1.setLineMapper(new DefaultLineMapper<Gdp>() {
        {
            setLineTokenizer(new DelimitedLineTokenizer() {
                {
                    setNames(new String[] { "region", "gdpExpend", "value" });
                }
            });
            setFieldSetMapper(new BeanWrapperFieldSetMapper<Gdp>() {
                {
                    setTargetType(Gdp.class);
                }
            });
        }
    });
    return reader1;
}

【问题讨论】:

  • 是的,你可以做到。您需要在 java 中编写大部分配置,而不是 xml
  • 我在 maven 中做了一个项目来完成这项工作,但在春季批次中没有做任何事情。你可以适应它。
  • @Panther 是的,我更喜欢 Java 配置,因为我们的项目正在使用它
  • @DiogodeGóesZanetti 当然,如果它符合我们的要求,我们可以调整它
  • @dazzle 希望我的回答对你有所帮助。

标签: spring spring-batch


【解决方案1】:

使用MultiResourceItemReader 扫描所有文件。
我认为您需要一种分类为 MultiResourceItemReader.delegate 的 ItemReader,但 SB 不提供,因此您必须自己编写。
对于 ItemProcessorItemWriter,SB 提供了分类器感知实现(ClassifierCompositeItemProcessorClassifierCompositeItemWriter)。
显然更多不同的输入文件,你必须编写更多的 XML 配置,但这应该很简单。

【讨论】:

  • 嗯,让我一步一步来。我如何只从 csv 中获取列标题。我已经把我的示例代码放在上面
  • 提取标题使用 FlatFileItemReader.setSkippedLinesCallback
  • 只是一个想法 - 在您保存列的地方使用自定义 bean。此 bean 由回调填充,您可以在自定义 LineMapper 中使用 if
  • @LucaBassoRicci - 请你在这里指导我 - stackoverflow.com/questions/64575208/…
【解决方案2】:

我想你期待这样的实现。

  1. 在 Partition Step Builder 期间,读取写入器的所有文件名、文件头、插入查询并将其保存在执行上下文中。

  2. 在从属步骤中,对于每个读取器和写入器,传递执行上下文,获取要读取的文件,将文件头发送到标记器,插入需要为该写入器插入的查询。

这解决了你的问题。

【讨论】:

    【解决方案3】:

    回答您的问题:

    1. 我不知道 Spring Batch 扫描文件的具体机制。
    2. 您可以将 opencsv 用作通用 CSV 阅读器,有很多读取文件的机制。

    关于 OpenCSV: 如果您使用的是 maven 项目,请尝试导入此依赖项:

     <dependency> 
       <groupId>net.sf.opencsv</groupId> 
       <artifactId>opencsv</artifactId> 
        <version>2.0</version> 
     </dependency> 
    

    您可以读取您的文件,为特定格式或通用标题创建对象,如下所示:

    private static List<DadosPeople> extrairDadosPeople() throws IOException {
        CSVReader readerPeople = new CSVReader(new FileReader(people));
        List<PeopleData> listPeople = new ArrayList<PeopleData>();
        String[] nextLine;
        while ((nextLine = readerPeople.readNext()) != null) {
            PeopleData people = new PeopleData();
            people.setIncludeData(nextLine[0]);
            people.setPartnerCode(Long.valueOf(nextLine[1]));
    
            listPeople.add(people);
        }
        readerPeople.close();
        return listPeople;
    }
    

    还有很多其他方法可以使用 opencsv 读取 CSV 文件:

    如果你想使用迭代器样式模式,你可以这样做:

     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
     String [] nextLine;
     while ((nextLine = reader.readNext()) != null) {
        // nextLine[] is an array of values from the line
        System.out.println(nextLine[0] + nextLine[1] + "etc...");
     }
    

    或者,如果您可能只想将全部内容放入列表中,只需调用 readAll()...

     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"));
     List myEntries = reader.readAll();
    

    这将为您提供可以迭代的 String[] 列表。如果一切都失败了,请在此处查看 Javadocs。 如果您想自定义引号字符和分隔符,您会发现可以提供您自己的分隔符和引号字符的构造函数。假设您使用制表符作为分隔符,您可以执行以下操作:

     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"), '\t');
    

    如果你单引用你的转义字符而不是双引号,你可以使用三个 arg 构造函数:

     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"), '\t', '\'');
    

    如果您知道内容直到文件后面才开始,您也可以跳过文件的前几行。因此,例如,您可以通过以下方式跳过前两行:

     CSVReader reader = new CSVReader(new FileReader("yourfile.csv"), '\t', '\'', 2);
    

    我可以用 opencsv 写 csv 文件吗?

    是的。在同一个包中有一个 CSVWriter,它遵循与 CSVReader 相同的语义。例如,要编写一个制表符分隔的文件:

     CSVWriter writer = new CSVWriter(new FileWriter("yourfile.csv"), '\t');
     // feed in your array (or convert your data to an array)
     String[] entries = "first#second#third".split("#");
     writer.writeNext(entries);
     writer.close();
    

    如果您更喜欢使用自己的引号字符,您可以使用构造函数的三个 arg 版本,它采用引号字符(或随意传入 CSVWriter.NO_QUOTE_CHARACTER)。

    您还可以自定义生成文件中使用的行终止符(这在您从 Linux Web 应用程序导出到 Windows 客户端时很方便)。为此目的有一个构造函数参数。 我可以将 SQL 表转储为 CSV 吗?

    是的,你可以。 CSVWriter 上有一个功能,因此您可以将 writeAll() 传递给 ResultSet。

     java.sql.ResultSet myResultSet = ....
     writer.writeAll(myResultSet, includeHeaders);
    

    有没有办法将我的 CSV 文件绑定到 Javabean 列表?

    是的,有。有一组类允许您根据列名、列位置或自定义映射策略将 CSV 文件绑定到 JavaBean 列表。您可以在 com.opencsv.bean 包中找到新类。以下是如何根据 CSV 文件中的字段位置映射到 java bean:

    ColumnPositionMappingStrategy strat = new ColumnPositionMappingStrategy();
    strat.setType(YourOrderBean.class);
    String[] columns = new String[] {"name", "orderNumber", "id"}; // the fields to bind do in your JavaBean
    strat.setColumnMapping(columns);
    
    CsvToBean csv = new CsvToBean();
    List list = csv.parse(strat, yourReader);
    

    【讨论】:

    • 这根本不是 Spring Batch。您在这里重新发明轮子,因为 Spring Batch 已经实现了整个 CSV 读取机制。
    • 正如我所回答的,我不知道执行此操作的“弹簧批处理方式”,但 opencsv 也可以读取和写入 csv 文件...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-25
    • 1970-01-01
    • 2020-04-23
    • 2012-10-02
    相关资源
    最近更新 更多