在java中获取csv文件维度的最快方法是什么
我在获取csv文件的维度任务时的常规过程如下:
- 获取它有多少行:
我使用while循环读取每一行,并通过每次成功读取计数。 缺点是读取整个文件需要花费时间来计算它有多少行。
- 然后得到它有多少列:我使用
String[] temp = lineOfText.split(",");
然后采取临时的大小。
有更聪明的方法吗? 喜欢:
file1 = read.csv;
xDimention = file1.xDimention;
yDimention = file1.yDimention;
您的方法不适用于多行值(您将获得无效的行数)和可能恰好包含分隔符的引用值(您将获得无效的列数)。
您应该使用CSV解析器,例如univocity-parsers提供的解析器 。
使用uniVocity CSV解析器,确定尺寸的最快方法是使用以下代码。 它解析一个150MB的文件 ,在1.2秒内给出它的尺寸:
// Let's create our own RowProcessor to analyze the rows static class CsvDimension extends AbstractRowProcessor { int lastColumn = -1; long rowCount = 0; @Override public void rowProcessed(String[] row, ParsingContext context) { rowCount++; if (lastColumn < row.length) { lastColumn = row.length; } } } public static void main(String... args) throws FileNotFoundException { // let's measure the time roughly long start = System.currentTimeMillis(); //Creates an instance of our own custom RowProcessor, defined above. CsvDimension myDimensionProcessor = new CsvDimension(); CsvParserSettings settings = new CsvParserSettings(); //This tells the parser that no row should have more than 2,000,000 columns settings.setMaxColumns(2000000); //Here you can select the column indexes you are interested in reading. //The parser will return values for the columns you selected, in the order you defined //By selecting no indexes here, no String objects will be created settings.selectIndexes(/*nothing here*/); //When you select indexes, the columns are reordered so they come in the order you defined. //By disabling column reordering, you will get the original row, with nulls in the columns you didn't select settings.setColumnReorderingEnabled(false); //We instruct the parser to send all rows parsed to your custom RowProcessor. settings.setRowProcessor(myDimensionProcessor); //Finally, we create a parser CsvParser parser = new CsvParser(settings); //And parse! All rows are sent to your custom RowProcessor (CsvDimension) //I'm using a 150MB CSV file with 1.3 million rows. parser.parse(new FileReader(new File("c:/tmp/worldcitiespop.txt"))); //Nothing else to do. The parser closes the input and does everything for you safely. Let's just get the results: System.out.println("Columns: " + myDimensionProcessor.lastColumn); System.out.println("Rows: " + myDimensionProcessor.rowCount); System.out.println("Time taken: " + (System.currentTimeMillis() - start) + " ms"); }
输出将是:
Columns: 7 Rows: 3173959 Time taken: 1279 ms
披露:我是这个图书馆的作者。 它是开源和免费的(Apache V2.0许可证)。
我想这取决于结构的规律性,以及你是否需要一个确切的答案。
我可以想象查看前几行(或随机跳过文件),然后将文件大小除以平均行大小以确定粗略的行数。
如果您控制这些文件的编写方式,您可以标记它们或在它们旁边添加包含行计数的元数据文件。
严格来说,你分割线的方式并没有涵盖所有可能的情况。 "hello, world", 4, 5
应该读作有3列,而不是4列。
IMO,你正在做的是一种可以接受的方式。 但是有一些方法可以让它更快:
- 而不是读取为每行创建一个新String对象的行,只需使用String.indexOf来查找行的边界
- 而不是使用line.split,再次使用indexOf来计算逗号的数量
- multithreading
我猜这里的选项取决于你如何使用数据:
- 写入文件时存储csv文件的尺寸(在第一行或在附加文件中)
- 使用更有效的方式来计算行数 – 也许是http://docs.oracle.com/javase/6/docs/api/java/io/LineNumberReader.html
- 而不是创建固定大小的数组(假设你需要的行数)使用数组列表 – 这可能会或可能不会更高效,具体取决于文件的大小。
要查找行数,您必须读取整个文件。 你在这里无能为力。 但是,找到cols数量的方法效率有点低。 而不是split
只是计算多少次“,”出现在行中。 您可能还包括@Vlad所述的配额中的字段的特殊条件。
String.split
方法创建一个字符串数组作为结果,并使用regexp进行拆分,这不是非常有效。
我在这里找到了这个简短而有趣的解决方案: https : //stackoverflow.com/a/5342096/4082824
LineNumberReader lnr = new LineNumberReader(new FileReader(new File("File1"))); lnr.skip(Long.MAX_VALUE); System.out.println(lnr.getLineNumber() + 1); //Add 1 because line index starts at 0 lnr.close();
我的解决方案是使用多行单元格或引用值简单而正确地处理CSV。
例如我们有csv文件:
1,"""2""","""111,222""","""234;222""","""""","1 2 3" 2,"""2""","""111,222""","""234;222""","""""","2 3" 3,"""5""","""1112""","""10;2""","""""","1 2"
我的解决方案片段是:
import java.io.*; public class CsvDimension { public void parse(Reader reader) throws IOException { long cells = 0; int lines = 0; int c; boolean qouted = false; while ((c = reader.read()) != -1) { if (c == '"') { qouted = !qouted; } if (!qouted) { if (c == '\n') { lines++; cells++; } if (c == ',') { cells++; } } } System.out.printf("lines : %d\n cells %d\n cols: %d\n", lines, cells, cells / lines); reader.close(); } public static void main(String args[]) throws IOException { new CsvDimension().parse(new BufferedReader(new FileReader(new File("test.csv")))); } }