【问题标题】:how to insert data into csv file using apche meta model?如何使用 apache 元模型将数据插入 csv 文件?
【发布时间】:2020-07-17 13:00:01
【问题描述】:

我在 java 项目中工作,我正在使用 apache 元模型将数据插入到 csv 文件中。

代码:

 public void insertIntoCSVFile(){
    File myFile = new File("unexisting_file.csv");    
    UpdateableDataContext dataContext = DataContextFactory.createCsvDataContext(myFile);
    final Schema schema = dataContext.getDefaultSchema();
    dataContext.executeUpdate(new UpdateScript() {
      public void run(UpdateCallback callback) {
    
        // CREATING A TABLE
        Table table = callback.createTable(schema, "my_table")
          .withColumn("name").ofType(VARCHAR)
          .withColumn("gender").ofType(CHAR)
          .withColumn("age").ofType(INTEGER)
          .execute();
     
        // INSERTING SOME ROWS
        callback.insertInto(table).value("name","John Doe").value("gender",'M').value("age",42).execute();
        callback.insertInto(table).value("name","Jane Doe").value("gender",'F').value("age",42).execute();
      }
    });
}

每当我为同一个 csv 文件调用此方法时,它都会成功插入数据,但会删除旧数据然后插入新数据,因此每次只插入两行。

我想通过多次调用函数来插入多个重复行,这意味着新行应该追加,旧行保持不变。

我怎样才能做到这一点?

【问题讨论】:

    标签: java apache-metamodel


    【解决方案1】:

    将表创建代码移到数据插入方法之外。每次在 CSV 文件中创建表格时,它都会覆盖之前的表格及其内容。

    这是一种方法:

    import java.io.File;
    import org.apache.metamodel.UpdateableDataContext;
    import org.apache.metamodel.csv.CsvDataContext;
    import org.apache.metamodel.DataContextFactory;
    import org.apache.metamodel.schema.Schema;
    import org.apache.metamodel.UpdateScript;
    import org.apache.metamodel.UpdateCallback;
    import org.apache.metamodel.schema.Table;
    import org.apache.metamodel.schema.ColumnType;
    
    public class App {
    
        public static void main(String[] args) {
            File myFile = new File("c:/tmp/unexisting_file.csv");
            UpdateableDataContext dataContext = DataContextFactory.createCsvDataContext(myFile);
            final Schema schema = dataContext.getDefaultSchema();
    
            final String tableName = "my_table";
            
            dataContext.executeUpdate(new UpdateScript() {
                @Override
                public void run(UpdateCallback callback) {
    
                    // CREATING A TABLE
                    Table table = callback.createTable(schema, tableName)
                            .withColumn("name").ofType(ColumnType.VARCHAR)
                            .withColumn("gender").ofType(ColumnType.CHAR)
                            .withColumn("age").ofType(ColumnType.INTEGER)
                            .execute();
                }
            });
    
            insertIntoCSVFile(dataContext, tableName);
            insertIntoCSVFile(dataContext, tableName);
        }
    
        public static void insertIntoCSVFile(final UpdateableDataContext dataContext,
                final String tableName) {
    
            dataContext.executeUpdate(new UpdateScript() {
                @Override
                public void run(UpdateCallback callback) {
    
                    String schemaName = dataContext.getDefaultSchema().getName();
                    Table table = dataContext.getTableByQualifiedLabel(schemaName + "." + tableName);
                          
                    // INSERTING SOME ROWS
                    callback.insertInto(table).value("name", "John Doe").value("gender", 'M').value("age", 42).execute();
                    callback.insertInto(table).value("name", "Jane Doe").value("gender", 'F').value("age", 42).execute();
                }
            });
        }
    }
    

    在本例中,main 方法负责创建表。然后这个方法调用两次数据插入方法,传入相关的上下文和表名。

    生成的文件内容为:

    "name","gender","age"
    "John Doe","M","42"
    "Jane Doe","F","42"
    "John Doe","M","42"
    "Jane Doe","F","42"
    

    有关详细信息,请参阅 creation of tables in CSV files 的语义 - 具体而言:

    使用(新)表结构创建或覆盖 CSV 文件。

    更新

    在尝试(再次)创建表之前,您可以通过检查表是否已存在来防止数据被覆盖。

    这是一个展示该方法的简单示例:

    首先,更改表名,使其与文件名匹配:

    final String tableName = "unexisting_file.csv";
    

    这是因为 MetaModel 使用它作为 CSV 文件中表的默认表名。我们可以使用它来检查我们是否已经创建了表:

    if (!tableExists()) {
        createTable();
    }
    

    使用上面的方法,这里是一个完整的例子:

    import org.apache.metamodel.UpdateableDataContext;
    import org.apache.metamodel.UpdateScript;
    import org.apache.metamodel.UpdateCallback;
    import org.apache.metamodel.schema.Table;
    import org.apache.metamodel.csv.CsvConfiguration;
    import org.apache.metamodel.csv.CsvDataContext;
    import org.apache.metamodel.schema.ColumnType;
    import org.apache.metamodel.util.Resource;
    import org.apache.metamodel.util.FileResource;
    
    public class CsvDemo {
    
        private final String tableName;
        private final UpdateableDataContext dataContext;
        
        public CsvDemo() {
            this.tableName = "example.csv";
            Resource resource = new FileResource("c:/tmp/" + tableName);
            CsvConfiguration configuration = new CsvConfiguration();
            this.dataContext = new CsvDataContext(resource, configuration);
        }
        
        public void doWork() {
            if (!tableExists()) {
                createTable();
            }
            appendData();
        }
    
        private boolean tableExists() {
            return getTable() != null;
        }
        
        private Table getTable() {
            return dataContext.getDefaultSchema().getTableByName(tableName);
        }
    
        private void createTable() {
            dataContext.executeUpdate(new UpdateScript() {
                @Override
                public void run(UpdateCallback callback) {
                    callback.createTable(dataContext.getDefaultSchema(), tableName)
                            .withColumn("name").ofType(ColumnType.VARCHAR)
                            .withColumn("gender").ofType(ColumnType.CHAR)
                            .withColumn("age").ofType(ColumnType.INTEGER)
                            .execute();
                }
            });
        }
        
        private void appendData() {
            dataContext.executeUpdate(new UpdateScript() {
                final Table table = getTable();
                @Override
                public void run(UpdateCallback callback) {
                    callback.insertInto(table).value("name", "John Doe")
                            .value("gender", 'M').value("age", 42).execute();
                    callback.insertInto(table).value("name", "Jane Doe")
                            .value("gender", 'F').value("age", 42).execute();
                }
            });
        }
    
    }
    

    现在,您将仅在 CSV 文件中创建该表(如果该表尚不存在)。如果它确实存在,那么您的附加数据将附加到文件中已经存在的任何数据中。

    【讨论】:

    • 它正在工作,但是当 main 方法执行时它会插入 4 行,如果我再次运行 main 方法,那么它会删除旧行并插入新行,那么我该如何实现呢?所以我希望每当我调用 main 方法时它应该插入新行而不删除旧行。
    • 如果我使用的是 openCSV,那么它可以工作。 CSV 文件以附加模式打开,因此每次数据都在追加而不是覆盖。字符串 csvFileName = "example.csv"; CSVWriter writer = new CSVWriter(new FileWriter(csvFileName, true));字符串 [] 记录 = "大卫,M,40".split(","); writer.writeNext(record); writer.close();那么我可以使用 apache 元模型来实现这一点吗?请提出建议。
    • 我添加了一个如何检查表是否已经存在的示例。这可以防止您多次创建表。
    • 我稍微清理了更新的示例,以更好地展示新的表格检查方法。
    • 出现错误:- java.lang.ClassNotFoundException: au.com.bytecode.opencsv.CSVReader in appendData() 中的插入语句。
    猜你喜欢
    • 2014-09-30
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    • 2015-03-29
    • 1970-01-01
    • 2016-11-07
    • 1970-01-01
    • 2014-05-03
    相关资源
    最近更新 更多