在 Java 中忽略读取 CSV 文件的空值

Ignoring null values reading a CSV file in Java

我能够读取我的数据集(csv 文件)但是当我 运行 我的主要 class 时,它显示所有行,包括具有空值的行。有没有办法忽略数据集中缺失值(即空值)的每一行? 我正在考虑在方法 testNullValue() 中检查它,但我真的不知道要检查什么。

我的Class

public static BufferedReader exTractTraningData(File datafile, String ListOfCharacteristics) throws IOException {

    try {
        //create BufferedReader to read csv file
        BufferedReader reader = new BufferedReader(new FileReader(datafile));

        String strLine = "";
        StringTokenizer st = null;

        int lineNumber = 0, tokenNumber = 0;;


        while ((strLine = reader.readLine()) != null) {
            lineNumber++;
            //break comma separated line using ","
            st = new StringTokenizer(strLine, ",");

            while (st.hasMoreTokens()) {
                //display csv values
                tokenNumber++;
                System.out.println("Line # " + lineNumber
                        + ", Token : " + st.nextToken(",") );
            }
            //reset token number
            tokenNumber = 0;;
        }
    } catch (Exception e) {

        System.out.println("Exception while reading csv file: " + e);
    }
    return null;
}

public boolean testNullValue(String ListOfCharacteristics, String ListOfValues){
    return false;


}

最后,我不明白为什么我的控制台中的结果没有像这样显示每一行 "name"、“2”、"TV "、"As "、“40” ,例如“10”,而我在这里指定它 st = new StringTokenizer(strLine, ",");

StringTokenizer 在遇到空值时会忽略空值,并且除了让分词器还提供定界符作为标记以及存在两个定界符标记之外,实际上无法知道它们实际上存在于 CSV 分隔字符串行中,一个接着一个,然后明显遇到了空值:

st = new StringTokenizer(strLine, ",", true); 

这是一种真正的 booger 检测 CSV 文件数据行中的 null 的方法,因为现在您必须提供代码来计算两个定界符标记何时相继出现并且然后完全忽略分隔符标记。这很可能是为什么没有太多人使用 StringTokenizer 来解析 CSV 文件而更喜欢使用 String#split() method instead or better yet a CSV Parser API like OpenCSV 之类的原因之一。这当然取决于真正需要做什么以及它的范围有多大。

实际上不鼓励在新代码中使用旧的遗留 StringTokenizer Class,因为它的方法不区分标识符、数字和带引号的字符串。 class 方法甚至无法识别和跳过评论。

无论如何,如果您想要检查任何单个 CSV 行中的任何空值,则无需重新读取文件。它可以在您当前正在执行的同一单次读取中完成。这个概念非常简单,利用一种代码机制来读取 CSV 文件数据行中的任何内容,将其拆分 到令牌中,令牌还维护可能包含在任何给定行中的空值,并且然后将该标记计数与使用 StringTokenizer 计数解析的同一数据文件行进行比较。这种事情可以在CSV数据行分词后直接做,例如:

while ((strLine = reader.readLine()) != null) {
    // You might want to count lines only if they are valid!
    // If so then move this line below the IF statement code 
    // block.
    lineNumber++;    
    //break comma separated line using ","
    st = new StringTokenizer(strLine, ",");

    // Is this a blank line OR Is there possibly a null token
    // in the data line detected by the String#split() method?
    if (st.countTokens() == 0 || (st.countTokens() != strLine.split(",").length)) {
        System.out.println("The data line is blank OR there is a null value "
                         + "in the data line!");
        // Skip this data line from further processing 
        // within the WHILE loop.
        continue;    
    }

    while (st.hasMoreTokens()) {
        //display csv values
        tokenNumber++;
        System.out.println("Line # " + lineNumber
                    + ", Token : " + st.nextToken(",") );
    }
    //reset token number
    tokenNumber = 0;
}

我个人只会使用 String#split() 方法,而不会费心使用 StringTokenizer class总而言之,也许是这样的,例如:

while ((strLine = reader.readLine()) != null) {
    // You might want to count lines only if they are valid!
    // If so then move this line below the IF statement code 
    // block.
    lineNumber++;    
    // Split comma separated line using ","
    String[] st = strLine.split(",");
    if (st.length == 0 || Arrays.asList(st).contains("")) {
        System.out.println("The data line (" + lineNumber + ") is blank OR "
                         + "there is a null value in the data line!");
        // Skip this data line from further processing 
        // within the WHILE loop.
        continue;
    }

    StringBuilder sb = new StringBuilder();
    sb.append("Line# ").append(lineNumber).append(": ");
    for (int i = 0; i < st.length; i++) {
        sb.append("Token : ").append(st[i]).
                // Ternary Operator used here to add commas
                append(i < (st.length-1) ? ", " : "");
    }
    System.out.println(sb.toString());      
}

当然,这一切都假设 CSV 文件数据是逗号分隔的,任何分隔符前后都没有空格。当人们 post 对数据文件处理提出疑问并且没有提供 示例 数据在该文件中的格式时,这就是问题所在。当然,这现在将我带到你的第二个问题,即为什么事情没有按照你想要的方式显示:

And Lastly, I don't why the results in my console is not displaying each rows like this "name", "2 ", "TV ", "As ", " 40", "10"

没有示例,谁知道数据在文件中的显示方式以及确切地您希望它如何在屏幕上显示。这个例子应该是什么,我个人不明白。此外,它不应该是 "name", "gender", "2 " ... ? 我们当然可以猜测,我的猜测是您在 StringTokenizer 方法中使用的定界符是错误的,当然,上面的所有示例都是基于您在自己的代码中提供的分隔符。