使用java使用大量数据更新csv中的特定列

使用java使用大量数据更新csv中的特定列,java,csv,Java,Csv,我有一个csv文件“主列表”,其中有800K条记录,每条记录有13个值。 单元格[0]和单元格[1]的组合给出了一个唯一的记录,我需要更新单元格[12]的值,即每个记录的状态 我有另一个csv文件,上面写着“更新的子集列表”。这是文件“主列表”的一个子集。对于我的第二个csv中数量较少的所有记录(比如10000条),我需要更新每个匹配记录的单元格[11]aka status列值 我尝试了commons csv中的direct BufferedReader、CsvParser和univocity.

我有一个csv文件“主列表”,其中有800K条记录,每条记录有13个值。 单元格[0]和单元格[1]的组合给出了一个唯一的记录,我需要更新单元格[12]的值,即每个记录的状态

我有另一个csv文件,上面写着“更新的子集列表”。这是文件“主列表”的一个子集。对于我的第二个csv中数量较少的所有记录(比如10000条),我需要更新每个匹配记录的单元格[11]aka status列值

我尝试了commons csv中的direct BufferedReader、CsvParser和univocity.parsers中的CsvParser。 但读取整个文件并创建800K的列表会导致内存不足异常

相同的代码将部署在不同的服务器上,所以我希望有一个高效的代码来读取巨大的csv文件并更新相同的文件

部分读取大文件并写入同一文件可能会损坏数据

你有什么建议吗

文件inputF=新文件(inputFilePath)

if(inputF.exists()){
InputStream inputFS=新文件InputStream(inputF);
BufferedReader br=新的BufferedReader(新的InputStreamReader(inputFS));
//跳过文件的标题
String line=br.readLine();
mandateList=新的ArrayList();
而((line=br.readLine())!=null){
添加(mapToItem(行));
}
br.close();
}

内存问题可以通过分块执行来解决。读一行和写一行可能会花费更多的时间。我没有试过,因为我的问题已经解决了,当时使用了成批的10万条记录,并在写入10万条记录后清除了列表

现在的问题是更新状态需要太多的循环

我有两个csv。主表(主列表)有800K记录,然后我有一个子集csv,也就是说它有10k记录。此csv子集是从其他系统更新的,其更新状态为“OK”和“NOT OK”。我需要在主控表中更新此状态。我怎样才能以最好的方式做到这一点???我使用的最愚蠢的方法是:

 // Master list have batches but it contains 800 k records and 12 columns
    List<DdMandates> mandatesList = new ArrayList<DdMandates>();
// Subset list have updated status 
List<DdMandates> updatedMandatesList = new ArrayList<DdMandates>();
// Read Subset csv file and map DdMandates item and then add to updated mandate list


    File inputF = new File(Property.inputFilePath);
if(inputF.exists()) {
InputStream inputFS = new FileInputStream(inputF);
BufferedReader br = new BufferedReader(new InputStreamReader(inputFS, "UTF-8"));

checkFilterAndmapToItem(br);

br.close();

In Method checkFilterAndmapToItem(BufferedReader br)

    private static void checkFilterAndmapToItem(BufferedReader br) {
        FileWriter fileWriter = null;
        try {
            // skip the header of the csv
            String line = br.readLine();
            int batchSize = 0, currentBatchNo=0;
            fileWriter = new FileWriter(Property.outputFilePath);
            //Write the CSV file header
            fileWriter.append(FILE_HEADER.toString());
            //Add a new line separator after the header
            fileWriter.append(NEW_LINE_SEPARATOR);
            if( !Property.batchSize.isEmpty()) {
                batchSize = Integer.parseInt(Property.batchSize.trim());
            }
            while ((line = br.readLine()) != null) {

                DdMandates item = new DdMandates(); 
                String[] p = line.concat(" ").split(SEPERATOR);
                Parse each p[x] and map to item of type DdMandates\
                        Iterating here on updated mandate list to check if this item is present in updated mandate list
                        then get that item and update that status to item . so here is a for loop for say 10K elements
                mandatesList.add(item);

                if (batchSize != 0 && mandatesList.size() == batchSize) {
                    currentBatchNo++;
                    logger.info("Batch  no. : "+currentBatchNo+" is executing...");
                    processOutputFile(fileWriter);
                    mandatesList.clear();
                }
            }
            processing output file here for the last batch ...
        }
//主列表有批处理,但它包含800k条记录和12列
List mandatesList=new ArrayList();
//子集列表已更新状态
List updatemandateslist=新建ArrayList();
//读取子集csv文件和映射项,然后添加到更新的任务列表中
File inputF=新文件(Property.inputFilePath);
if(inputF.exists()){
InputStream inputFS=新文件InputStream(inputF);
BufferedReader br=新的BufferedReader(新的InputStreamReader(inputFS,“UTF-8”));
检查过滤器和映射项(br);
br.close();
方法内检查过滤器和映射项(BufferedReader br)
专用静态无效检查筛选器和映射项(BufferedReader br){
FileWriter FileWriter=null;
试一试{
//跳过csv的标题
String line=br.readLine();
int batchSize=0,currentBatchNo=0;
fileWriter=新的fileWriter(Property.outputFilePath);
//写入CSV文件头
追加(FILE_HEADER.toString());
//在页眉后添加新行分隔符
追加(新的行分隔符);
如果(!Property.batchSize.isEmpty()){
batchSize=Integer.parseInt(Property.batchSize.trim());
}
而((line=br.readLine())!=null){
DDOrderations item=新DDOrderations();
字符串[]p=line.concat(“”).split(分隔符);
解析每个p[x]并映射到DDX类型的项\
在更新的授权列表上迭代此处,以检查更新的授权列表中是否存在此项
然后获取该项目并将其状态更新为该项目
强制列表。添加(项目);
if(batchSize!=0&&mandatesList.size()==batchSize){
currentBatchNo++;
logger.info(“批号:“+currentBatchNo+”正在执行…”);
processOutputFile(fileWriter);
mandatesList.clear();
}
}
正在此处处理最后一批的输出文件。。。
}
它将有while循环(800k迭代){每个元素的内部循环10K迭代)

所以至少800K*10K环路

请帮助我们找到最好的方法,减少迭代


提前感谢

假设您正在批量读取50K的“主数据文件”:

  • 使用单元格[0]和单元格[1]作为键,其余列作为值,在java中存储此数据

  • 大多数情况下,get和put的复杂性为O(1)

  • 因此,在特定批次中搜索10K记录的复杂性将是O(10K)

    HashMap hmap=newhashmap();
    
  • 使用key=ddrequirements.get(0)+ddrequirements.get(1)

注意:如果50K记录超过HashMap的内存限制,则创建较小的批

  • 为了进一步提高性能,您可以通过创建小批量并在不同线程上处理它们来使用多线程

第一个建议是,当您创建
ArrayList
时,它将使列表容量为10。因此,如果您处理大量数据,请首先对其进行初始化,如下所示:

private static final int LIST_CAPACITY = 800000;
mandatesList = new ArrayList<DdMandates>(LIST_CAPACITY);

阅读一个大的csv文件从来都不是一个好主意,你应该一块一块地读。@raviraja,谢谢,我也想到过同样的方法,但我说我正在读一次50k的批,搜索10K记录,在另一个新的csv文件中更新,然后在下一个50k记录中搜索相同的10K记录等等。这太耗费时间了。性能受到影响d在这种情况下会产生负面影响。使用数据库。这就是它们的用途。按照建议使用数据库。但您可能希望尝试将csv连接为数据库的方法。例如,您将能够运行正常的SQL查询。这仅用于将输出读写到另一个文件
HashMap<String, DdMandates> hmap = new HashMap<String, DdMandates>();
private static final int LIST_CAPACITY = 800000;
mandatesList = new ArrayList<DdMandates>(LIST_CAPACITY);
FileInputStream inputStream = null;
Scanner sc = null;
try {
    inputStream = new FileInputStream(path);
    sc = new Scanner(inputStream, "UTF-8");
    while (sc.hasNextLine()) {
        String line = sc.nextLine();
        /* your business rule here */
    }
    // note that Scanner suppresses exceptions
    if (sc.ioException() != null) {
        throw sc.ioException();
    }
} finally {
    if (inputStream != null) {
        inputStream.close();
    }
    if (sc != null) {
        sc.close();
    }
}