【问题标题】:Java Add Column with calculation to CSV fileJava将计算列添加到CSV文件
【发布时间】:2017-02-25 19:22:36
【问题描述】:

如何在 CSV 文件中添加新列,并在每列中添加计算数据?

例子

userid,expDate 1,012015 2,022016 3,032018

我会从每一行中获取 expDate,相对于当前月份和年份计算它以获得多少个月才能到期,然后取整monthsTill(所以下个月的monthsTill 将为1,无论它是第一天还是最后一天当月)

userid,expDate,monthsTill 1,022017,0 2,032017,1 3,042017,2 3,052017,3

你将如何“跳过”在相应列中具有特定值的行?

【问题讨论】:

  • 您是否愿意使用外部库,例如 apache commons csv 和 apache commons io ?
  • 我宁愿让代码尽可能简单,如果 apache commons 有助于做到这一点并且可以轻松使用,我愿意接受。

标签: java csv duration


【解决方案1】:

根据你的伪代码,这就是应该做的事情

private void process(){
    BufferedReader bufferedReader = null;
    PrintWriter p = null;
    String sep = ",";
    String newCol = "monthsTill";
    String defaultTillExpMonth = ">3";
    Calendar cal = Calendar.getInstance();
    cal.setTime(new Date());
    int currMonth = cal.get(Calendar.MONTH) + 1;
    try {
    // read csv file
    List<String> input = new ArrayList<String>();
   File inputFile = new File("InputFile");
  bufferedReader = new BufferedReader(new FileReader(inputFile));
    String readLine = "";
    while ((readLine = bufferedReader.readLine()) != null) {
        input.add(readLine);
    }

 // for each row after first row
    // calculate timeTillExpired
        // if format MYYYY (ex 22017)
            // M and YYYY -> MM and YYYY

       // calculate relative to current date as months

    int numOfRecords = input.size();
    if(numOfRecords>1){
        List<String> output = new ArrayList<String>();
        String header = input.get(0) +sep +newCol;
        output.add(header);

        // for each row after first row
        // calculate timeTillExpired
        // if format MYYYY (ex 22017)
              // M and YYYY -> MM and YYYY
        // calculate relative to current date as months
        for(int i=1;i<numOfRecords;i++){
            // I am simply going to get the last column from record
            String row = input.get(i);
            StringBuilder res = new StringBuilder(row);
            String [] entries = row.split(sep);
            int length = entries.length;
            if(length>0){
                res.append(sep);
                String rec = entries[length-1];
                int expMonth = 0;
                // Case of MYYYY. Assumption is it's either MYYYY or MMYYYY
                if(rec.length()==5){
                    expMonth = Integer.valueOf(rec.substring(0, 1));
                } else {
                    expMonth = Integer.valueOf(rec.substring(0, 2));
                }

                int monToExp = expMonth - currMonth;
                // if calculated > 3
                if(monToExp > 3){
                    res.append(defaultTillExpMonth);
                } else {
                    res.append(monToExp);
                }
                output.add(res.toString());
            }
        }
        // Write into the same file.
        // First We'll delete everything in the input file and then write the modified records

        p = new PrintWriter(new FileWriter("output.txt",false));
        // Ouch. Very bad way to handle resources. You should find a better way
        p.print("");
        p.close();
        // Write into file
        p = new PrintWriter(new FileWriter("InputFile"));
        for(String row : output)
        {
            p.println(row);
        }



    } else {
        System.out.println("No records to process");
    }



    } catch(IOException e){
        e.printStackTrace();
    } finally { // Close file
        if(p!=null){
            p.close();
        }
        if(bufferedReader!=null){
            try {
                bufferedReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

我强烈建议您了解什么是文件资源,如何有效地处理它们并改进此代码。稍后您应该转到 Apache Commons Library

【讨论】:

  • 如何确保它只从我的数据文件的第 13 列获取数据?我只是花了一些时间并编写了一个单独的函数,该函数从该列获取输入并输出一个时间到几个月的例子,它将在 22017 年,当前日期和年份是 22017,所以它会输出 0,下个月发送 int 22017 和它会输出 1
  • 如果将计算时间的内容与记录中的内容分开,对我来说会更容易。
  • 我在您的伪代码下发表了评论。无论如何,您可以替换 if(length>0) , String rec = entries[length-1];使用 if(length>12) 和 String rec = entries[12];
  • 我同意。计算时间的逻辑应该是一个独立的独立函数。
  • 移动3条语句LocalDate expDate = new LocalDate(yearResult, monthResult, day); LocalDate currDate = new LocalDate(); int 输出 = Months.monthsBetween(expDate, currDate).getMonths();在 if else 块之外并调用该方法
【解决方案2】:

我还没有测试过,但是下面的代码应该可以解决你的问题。

List<String> input = FileUtils.readLines(new File("SomeFile"), StandardCharsets.UTF_8);
    List<String> output = new ArrayList<String>();
    if(input.size()>1){
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int month = cal.get(Calendar.MONTH) + 1;
        String header = input.get(0) + ",monthsTill";
        output.add(header);
        int length = input.size();
        for(int i=1;i<length;i++){
            StringBuilder str = new StringBuilder();
            String row = input.get(i);
            String [] elements = row.split(",");
            if(elements.length == 2){
             // You have access to both the index and expiry date. So if you want to skip some row, simply don't add it to the ouput collection
                int exp = Integer.parseInt(elements[1].substring(0, 2));
                int monRemaining = month-exp;
                str.append(row).append(",").append(monRemaining);
                output.add(str.toString());
            } else {
                throw new IllegalArgumentException();
            }
        }

        FileUtils.writeLines(new File("SomeFile"), output, false);

请注意,'FileUtils' 类来自 APache Commons IO 包

编辑:如果您不想使用 FileUtils,请替换

List<String> input = FileUtils.readLines(new File("SomeFile"), StandardCharsets.UTF_8);

List<String> input = new ArrayList<String>();
       File inputFile = new File("SomeFile");
       BufferedReader bufferedReader = new BufferedReader(new FileReader(inputFile));
       String readLine = "";
       while ((readLine = bufferedReader.readLine()) != null) {
           input.add(readLine);
       }

 FileUtils.writeLines(new File("SomeFile"), output, false);

PrintWriter f0 = new PrintWriter(new FileWriter("SomeFile",false));
        f0.print("");
        // Erase the contents of the input file in a
        // Very bad way
        f0.close();
        f0 = new PrintWriter(new FileWriter("output.txt"));
        for(String row : output)
        {
            f0.println(row);
        }
        f0.close();

当然,如果您不使用 Apache Commons IO,您将不得不自己处理诸如流等关闭资源。

【讨论】:

  • 在没有 apache commons 的情况下可以做到这一点吗?我找不到 org.apache.commons.io.FileUtils。
  • Apache Commons 不是 Java SDK 的一部分。您可以将其用作外部 Jar 或使用 Maven 之类的构建工具 - mvnrepository.com/artifact/commons-io/commons-io/2.4
  • 我得到了所有文件,但在 throw new IllegalArgumentException(); 时出错
  • if(elements.length == 2) 检查是否正好有 2 个用逗号分隔的值。您输入的 csv 文件是否正确?
  • 那是大体思路的一个样本,实际数据中有13列
【解决方案3】:

这是我正在尝试做的一些伪代码

    // read csv file
        // append timeTillExpired to end of first row of CSV
        // for each row after first row
            // calculate timeTillExpired
                // if format MYYYY (ex 22017)
                    // M and YYYY
                    // calculate relative to current date as months
                //else
                    // MM and YYYY (ex 122017)
                    // calculate relative to current date as months
            // if calculated > 3
                // timeTillExpired = ">3"
                // add timeTillExpired to end of row
            //else
                // add timeTillExpired to end of row
    // save file
    // close file

【讨论】:

  • 如何(在什么基础上?)/你在哪里跳过行?
【解决方案4】:

这是我的计算时间的函数

private static int calculateTimeTill(int date) 
{
    // TODO Auto-generated method stub
    String numberAsString = Integer.toString(date);
    if(numberAsString.length() == 5)
    {
        //format 22017
        String month = numberAsString.substring(0,1);
        String year = numberAsString.substring(1,5);
        int monthResult = Integer.parseInt(month);
        int yearResult = Integer.parseInt(year);
        int day = 1;
        // using Joda - Time http://joda-time.sourceforge.net/installation.html
        // downloaded Joda - Convert as well
        LocalDate expDate = new LocalDate(yearResult, monthResult, day);
        LocalDate currDate = new LocalDate();
        int output = Months.monthsBetween(expDate, currDate).getMonths();
        return output;
    }
    else
    {
        //format 122017
        String month = numberAsString.substring(0,2);
        String year = numberAsString.substring(2,6);
        int monthResult = Integer.parseInt(month);
        int yearResult = Integer.parseInt(year);
        int day = 1;
        // using Joda - Time http://joda-time.sourceforge.net/installation.html
        // downloaded Joda - Convert as well
        LocalDate expDate = new LocalDate(yearResult, monthResult, day);
        LocalDate currDate = new LocalDate();
        int output = Months.monthsBetween(expDate, currDate).getMonths();
        return output;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    相关资源
    最近更新 更多