逐列读取 CSV 文件

Posted

技术标签:

【中文标题】逐列读取 CSV 文件【英文标题】:Read CSV file column by column 【发布时间】:2012-08-23 12:55:02 【问题描述】:

我想从多列 csv 文件中读取特定列,并使用 Java 在其他 csv 文件中打印这些列。请问有什么帮助吗?以下是我逐行打印每个标记的代码。但我希望只打印多列 csv 中的几列。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.StringTokenizer;

public class ParseCSV 

    public static void main(String[] args) 

        try
        

            //csv file containing data
            String strFile = "C:\\Users\\rsaluja\\CMS_Evaluation\\Drupal_12_08_27.csv";

            //create BufferedReader to read csv file
            BufferedReader br = new BufferedReader( new FileReader(strFile));
            String strLine = "";
            StringTokenizer st = null;
            int lineNumber = 0, tokenNumber = 0;

            //read comma separated file line by line
            while( (strLine = br.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 # " + tokenNumber
                                + ", Token : "+ st.nextToken());


                            System.out.println(cols[4]);

【问题讨论】:

然后只打印几列,然后阅读(但跳过)你不需要的那些...... 呃。即使在 Windows /Users/rsaluja/CMS_Eval... 上,Java 也可以将正斜杠 / 用于路径,因此您不必加倍来转义反斜杠。 是的,可以使用正斜杠;) 【参考方案1】:

您应该使用出色的OpenCSV 来读写 CSV 文件。为了调整您的示例以使用该库,它看起来像这样:

public class ParseCSV 
  public static void main(String[] args) 
    try 
      //csv file containing data
      String strFile = "C:/Users/rsaluja/CMS_Evaluation/Drupal_12_08_27.csv";
      CSVReader reader = new CSVReader(new FileReader(strFile));
      String [] nextLine;
      int lineNumber = 0;
      while ((nextLine = reader.readNext()) != null) 
        lineNumber++;
        System.out.println("Line # " + lineNumber);

        // nextLine[] is an array of values from the line
        System.out.println(nextLine[4] + "etc...");
      
    
  

【讨论】:

+1 同意。尝试拼凑一些代码行来解析 CSV 数据通常会以大喊大叫和流泪告终。对于 CSV,请使用专为该作业设计的 API。 是的,同意。我可以使用 Open Csv。但我正在寻找的是我只需要选择性列。我已经使用所有标记正确解析了文件,但它逐行解析,在这里我正在寻找读取,然后只打印出少数选定的特定列。无论如何感谢您的回复! :) “但我正在寻找的是我只需要选择性列。” 这绝不排除使用 API,所以我对你为什么开始感到困惑它与 “但是..”. 对于只需要从 CSV 读取特定列的给定要求,不需要复杂的处理和写入,添加 OpenCSV 库不是矫枉过正吗?只是想知道...... 这显然是个人意见,但我想说这并不过分,因为有多少外部变量(CSV 文件的内容)可能威胁到程序的稳定性。作为参考,请查看 CSVReader 源,因为对于库其余部分的“权重”,OpenCSV 仍然做了很多工作。另一个考虑因素是更大程度地追求将您编写的代码保持在最少的数量和最大的表现力。不是每个人都认为这是一个目标,但在我看来,这是构建可持续系统的唯一途径。【参考方案2】:

读取 CSV 文件非常简单,在 Java 中很常见。您实际上不需要加载任何额外第三方库来为您执行此操作。 CSV(逗号分隔值)文件只是一个普通的纯文本文件,按列存储数据,并用分隔符(例如逗号“,”)将其分割。

为了从 CSV 文件中读取特定列,有几种方法。最简单的如下:

无需任何第三方库即可读取 CSV 的代码

BufferedReader br = new BufferedReader(new FileReader(csvFile));
while ((line = br.readLine()) != null) 
    // use comma as separator
    String[] cols = line.split(cvsSplitBy);
    System.out.println("Coulmn 4= " + cols[4] + " , Column 5=" + cols[5]);

如果您注意到,这里没有执行任何 特殊。它只是读取一个文本文件,然后用分隔符“,”将其吐出。

考虑从GeoLite Free Downloadable Databases 的旧国家/地区 CSV 数据中提取

"1.0.0.0","1.0.0.255","16777216","16777471","AU","Australia"
"1.0.1.0","1.0.3.255","16777472","16778239","CN","China"
"1.0.4.0","1.0.7.255","16778240","16779263","AU","Australia"
"1.0.8.0","1.0.15.255","16779264","16781311","CN","China"
"1.0.16.0","1.0.31.255","16781312","16785407","JP","Japan"
"1.0.32.0","1.0.63.255","16785408","16793599","CN","China"
"1.0.64.0","1.0.127.255","16793600","16809983","JP","Japan"
"1.0.128.0","1.0.255.255","16809984","16842751","TH","Thailand"

上面的代码会输出如下:

Column 4= "AU" , Column 5="Australia"
Column 4= "CN" , Column 5="China"
Column 4= "AU" , Column 5="Australia"
Column 4= "CN" , Column 5="China"
Column 4= "JP" , Column 5="Japan"
Column 4= "CN" , Column 5="China"
Column 4= "JP" , Column 5="Japan"
Column 4= "TH" , Column 5="Thailand"

实际上,您可以 put Map 中的列,然后只需使用 key 即可获取值。

希希尔

【讨论】:

这么简单?当值中有逗号时,您的示例会中断。例如。 "1,0,0,0","1.0.0.255","16777216" 不起作用(但它是一个有效的 csv 文件)。这就是为什么使用专门设计的 api 可以让您的生活更轻松的原因,这些边缘案例已经过思考和(希望)测试。 我同意@cowls 这取决于您对系统和用例的了解程度。当您知道输入 CSV 不会有边缘情况时,您不需要一个库来阅读它。 这里行的数据类型是什么?【参考方案3】:

很抱歉,这些答案都没有提供最佳解决方案。如果您使用 OpenCSV 等库,您将不得不编写大量代码来处理特殊情况以从特定列中提取信息。

例如,如果您的行数少于您所要的列数,您将不得不编写大量代码来处理它。使用 OpenCSV 示例:

  CSVReader reader = new CSVReader(new FileReader(strFile));
  String [] nextLine;
  while ((nextLine = reader.readNext()) != null) 
       //let's say you are interested in getting columns 20, 30, and 40
       String[] outputRow = new String[3];
       if(parsedRow.length < 40)
            outputRow[2] = null;
        else 
            outputRow[2] = parsedRow[40]
       
       if(parsedRow.length < 30)
            outputRow[1] = null;
        else 
            outputRow[1] = parsedRow[30]
       
       if(parsedRow.length < 20)
            outputRow[0] = null;
        else 
            outputRow[0] = parsedRow[20]
       

  

这是一个简单需求的大量代码。如果您试图按名称获取列的值,情况会变得更糟。您应该使用更现代的解析器,例如 uniVocity-parsers 提供的解析器。

要可靠且轻松地获得所需的列,只需编写:

CsvParserSettings settings = new CsvParserSettings();
parserSettings.selectIndexes(20, 30, 40);
CsvParser parser = new CsvParser(settings);
List<String[]> allRows = parser.parseAll(new FileReader(yourFile));

披露:我是这个库的作者。它是开源免费的(Apache V2.0 许可)。

【讨论】:

【参考方案4】:

我建议使用 Apache Commons CSV https://commons.apache.org/proper/commons-csv/

这是一个例子:

    Path currentRelativePath = Paths.get("");
    String currentPath = currentRelativePath.toAbsolutePath().toString();
    String csvFile = currentPath + "/pathInYourProject/test.csv";

    Reader in;
    Iterable<CSVRecord> records = null;
    try
    
        in = new FileReader(csvFile);
        records = CSVFormat.EXCEL.withHeader().parse(in); // header will be ignored
    
    catch (IOException e)
    
        e.printStackTrace();
    

    for (CSVRecord record : records) 
        String line = "";
        for ( int i=0; i < record.size(); i++)
        
            if ( line == "" )
                line = line.concat(record.get(i));
            else
                line = line.concat("," + record.get(i));
        
        System.out.println("read line: " + line);
    

它会自动识别",但不识别(也许可以配置...)。

我的示例文件是:

col1,col2,col3
val1,"val2",val3
"val4",val5
val6;val7;"val8"

输出是:

read line: val1,val2,val3
read line: val4,val5
read line: val6;val7;"val8"

最后一行被认为是一个值。

【讨论】:

【参考方案5】:

阅读一些特定的专栏 我做了这样的事情:

dpkcs.csv content:
FN,LN,EMAIL,CC
Name1,Lname1,email1@gmail.com,CC1
Nmae2,Lname2,email2r@gmail.com,CC2

读取函数:

private void getEMailRecepientList() 
                List<EmailRecepientData> emailList = null;// Blank list of POJO class
                Scanner scanner = null;
                BufferedReader reader = null;
                try 
                    reader = new BufferedReader(new FileReader("dpkcs.csv"));
                    Map<String, Integer> mailHeader = new HashMap<String, Integer>();
                    // read file line by line
                    String line = null;
                    int index = 0;
                    line = reader.readLine();
                    // Get header from 1st row of csv
                    if (line != null) 
                        StringTokenizer str = new StringTokenizer(line, ",");
                        int headerCount = str.countTokens();
                        for (int i = 0; i < headerCount; i++) 
                            String headerKey = str.nextToken();
                            mailHeader.put(headerKey.toUpperCase(), new Integer(i));

                        
                    
                    emailList = new ArrayList<EmailRecepientData>();

                    while ((line = reader.readLine()) != null) 
                    // POJO class for getter and setters
                        EmailRecepientData email = new EmailRecepientData();
                        scanner = new Scanner(line);
                        scanner.useDelimiter(",");
                    //Use Specific key to get value what u want
                        while (scanner.hasNext()) 
                            String data = scanner.next();
                            if (index == mailHeader.get("EMAIL"))
                                email.setEmailId(data);
                            else if (index == mailHeader.get("FN"))
                                email.setFirstName(data);
                            else if (index == mailHeader.get("LN"))
                                email.setLastName(data);
                            else if (index == mailHeader.get("CC"))
                                email.setCouponCode(data);

                            index++;
                        
                        index = 0;
                        emailList.add(email);
                    
                    reader.close();
                 catch (Exception e) 
                    StringWriter stack = new StringWriter();
                    e.printStackTrace(new PrintWriter(stack));

                 finally 
                    scanner.close();
                

                System.out.println("list--" + emailList);

            

POJO 类:

public class EmailRecepientData 
    private String emailId;
    private String firstName;
    private String lastName;
    private String couponCode;

    public String getEmailId() 
        return emailId;
    

    public void setEmailId(String emailId) 
        this.emailId = emailId;
    

    public String getFirstName() 
        return firstName;
    

    public void setFirstName(String firstName) 
        this.firstName = firstName;
    

    public String getLastName() 
        return lastName;
    

    public void setLastName(String lastName) 
        this.lastName = lastName;
    

    public String getCouponCode() 
        return couponCode;
    

    public void setCouponCode(String couponCode) 
        this.couponCode = couponCode;
    

    @Override
    public String toString() 
        return "Email Id=" + emailId + ", First Name=" + firstName + " ,"
                + " Last Name=" + lastName + ", Coupon Code=" + couponCode + "";
    


【讨论】:

编辑此部分以获得每一行的所需列:else if (index == mailHeader.get("COULUM_NAME")) syso(data)【参考方案6】:

我们可以单独使用核心 java 的东西来逐列读取 CVS 文件。这是我为我的要求编写的示例代码。我相信它会对某些人有所帮助。

 BufferedReader br = new BufferedReader(new FileReader(csvFile));
    String line = EMPTY;
    int lineNumber = 0;

    int productURIIndex = -1;
    int marketURIIndex = -1;
    int ingredientURIIndex = -1;
    int companyURIIndex = -1;

    // read comma separated file line by line
    while ((line = br.readLine()) != null) 
        lineNumber++;
        // use comma as line separator
        String[] splitStr = line.split(COMMA);
        int splittedStringLen = splitStr.length;

        // get the product title and uri column index by reading csv header
        // line
        if (lineNumber == 1) 
            for (int i = 0; i < splittedStringLen; i++) 
                if (splitStr[i].equals(PRODUCTURI_TITLE)) 
                    productURIIndex = i;
                    System.out.println("product_uri index:" + productURIIndex);
                

                if (splitStr[i].equals(MARKETURI_TITLE)) 
                    marketURIIndex = i;
                    System.out.println("marketURIIndex:" + marketURIIndex);
                

                if (splitStr[i].equals(COMPANYURI_TITLE)) 
                    companyURIIndex = i;
                    System.out.println("companyURIIndex:" + companyURIIndex);
                

                if (splitStr[i].equals(INGREDIENTURI_TITLE)) 
                    ingredientURIIndex = i;
                    System.out.println("ingredientURIIndex:" + ingredientURIIndex);
                
            
         else 
            if (splitStr != null) 
                String conditionString = EMPTY;
                // avoiding arrayindexoutboundexception when the line
                // contains only ,,,,,,,,,,,,,
                for (String s : splitStr) 
                    conditionString = s;
                
                if (!conditionString.equals(EMPTY)) 
                    if (productURIIndex != -1) 
                        productCVSUriList.add(splitStr[productURIIndex]);
                    
                    if (companyURIIndex != -1) 
                        companyCVSUriList.add(splitStr[companyURIIndex]);
                    
                    if (marketURIIndex != -1) 
                        marketCVSUriList.add(splitStr[marketURIIndex]);
                    
                    if (ingredientURIIndex != -1) 
                        ingredientCVSUriList.add(splitStr[ingredientURIIndex]);
                    
                
            
        

【讨论】:

【参考方案7】:

查找文件夹中的所有文件并将该数据写入 ArrayList 行。

初始化

ArrayList<ArrayList<String>> row=new ArrayList<ArrayList<String>>();
BufferedReader br=null;

用于访问行

for(ArrayList<String> data:row)
data.get(col no); 

or row.get(0).get(0) // getting first row first col

从文件夹中读取所有文件并将它们连接到行的函数。

static void readData()
String path="C:\\Users\\Galaxy Computers\\Desktop\\Java project\\Nasdaq\\";
File files=new File(path);
String[] list=files.list();

try 
        String sCurrentLine;
       char check;
       for(String filename:list) 
        br = new BufferedReader(new FileReader(path+filename));
        br.readLine();//If file contains uneccessary first line.
        while ((sCurrentLine = br.readLine()) != null) 

           row.add(splitLine(sCurrentLine));
        
        
        

     catch (IOException e) 
        e.printStackTrace();
     
        try 
            if (br != null)br.close();
         catch (IOException ex) 
            ex.printStackTrace();
        
    


   static ArrayList<String> splitLine(String line)
   String[] ar=line.split(",");
   ArrayList<String> d=new ArrayList<String>();
   for(String data:ar)
    d.add(data);
   

   return d; 
    

【讨论】:

【参考方案8】:

好吧,这个怎么样!!

此代码计算 csv 文件中的行数和列数。试试这个!!

    static int[] getRowsColsNo() 
    Scanner scanIn = null;
    int rows = 0;
    int cols = 0;
    String InputLine = "";
    try 
        scanIn = new Scanner(new BufferedReader(
                new FileReader("filename.csv")));
        scanIn.useDelimiter(",");
        while (scanIn.hasNextLine()) 
            InputLine = scanIn.nextLine();
            String[] InArray = InputLine.split(",");
            rows++;
            cols = InArray.length;
        

     catch (Exception e) 
        System.out.println(e);
    
    return new int[]  rows, cols ;

【讨论】:

如果 col 值本身包含逗号,此方法将失败。

以上是关于逐列读取 CSV 文件的主要内容,如果未能解决你的问题,请参考以下文章

Pig:读取多个文件并逐列追加

请教一下:python 如何按列读取的?

gh读取csv文件

vb.net 怎么生成csv文件与怎么读取csv文件

ruby读取csv文件数据

vb如何实时读取csv文件?