在 java 中获取 csv 文件尺寸的最快方法是什么
what is the fastest way to get dimensions of a csv file in java
我执行获取 csv 文件尺寸任务时的常规程序如下:
- 获取它有多少行:
我使用 while 循环来读取每一行并计算每次成功读取的次数。缺点是读取整个文件只是为了计算它有多少行需要时间。
- 然后获取它有多少列:
我使用
String[] temp = lineOfText.split(",");
然后取 temp. 的大小
有什么更聪明的方法吗?喜欢:
文件 1 = read.csv;
x维度 = file1.xDimention;
y维度 = file1.yDimention;
我想这取决于结构的规则程度,以及您是否需要准确的答案。
我可以想象查看前几行(或随机跳过文件),然后将文件大小除以平均行大小以确定粗略的行数。
如果您控制这些文件的写入方式,您可能会标记它们或在它们旁边添加一个包含行数的元数据文件。
严格来说,您分割线的方式并没有涵盖所有可能的情况。 "hello, world", 4, 5
应该读作有 3 列,而不是 4。
要查找行数,您必须阅读整个文件。在这里你无能为力。但是,您查找 cols 数量的方法效率有点低。而不是 split
只计算“,”在该行中出现的次数。您还可以在此处包括有关@Vlad 提到的配额中的字段的特殊条件。
String.split
方法创建一个字符串数组作为结果,并使用效率不高的正则表达式进行拆分。
IMO,你正在做的是一种可以接受的方式。但这里有一些方法可以让它更快:
- 与其读取行,它为每一行创建一个新的字符串对象,不如使用 String.indexOf 来查找行的边界
- 而不是使用 line.split,再次使用 indexOf 来计算逗号的数量
- 多线程
我想这些选项取决于您如何使用数据:
- 写入文件时存储 csv 文件的尺寸(在第一行或附加文件中)
- 使用更有效的方式来计算行数 - 也许 http://docs.oracle.com/javase/6/docs/api/java/io/LineNumberReader.html
- 不要创建固定大小的数组(假设这就是您需要行数的原因),而是使用数组列表 - 这可能更有效也可能不会更有效,具体取决于文件的大小。
您的方法不适用于多行值(您将获得无效的行数)和可能恰好包含分隔符的引用值(您将获得无效的列数)。
您应该使用 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 许可证)。
我在这里找到了这个简短但有趣的解决方案:
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"))));
}
}
我执行获取 csv 文件尺寸任务时的常规程序如下:
- 获取它有多少行:
我使用 while 循环来读取每一行并计算每次成功读取的次数。缺点是读取整个文件只是为了计算它有多少行需要时间。
- 然后获取它有多少列:
我使用
String[] temp = lineOfText.split(",");
然后取 temp. 的大小
有什么更聪明的方法吗?喜欢:
文件 1 = read.csv;
x维度 = file1.xDimention;
y维度 = file1.yDimention;
我想这取决于结构的规则程度,以及您是否需要准确的答案。
我可以想象查看前几行(或随机跳过文件),然后将文件大小除以平均行大小以确定粗略的行数。
如果您控制这些文件的写入方式,您可能会标记它们或在它们旁边添加一个包含行数的元数据文件。
严格来说,您分割线的方式并没有涵盖所有可能的情况。 "hello, world", 4, 5
应该读作有 3 列,而不是 4。
要查找行数,您必须阅读整个文件。在这里你无能为力。但是,您查找 cols 数量的方法效率有点低。而不是 split
只计算“,”在该行中出现的次数。您还可以在此处包括有关@Vlad 提到的配额中的字段的特殊条件。
String.split
方法创建一个字符串数组作为结果,并使用效率不高的正则表达式进行拆分。
IMO,你正在做的是一种可以接受的方式。但这里有一些方法可以让它更快:
- 与其读取行,它为每一行创建一个新的字符串对象,不如使用 String.indexOf 来查找行的边界
- 而不是使用 line.split,再次使用 indexOf 来计算逗号的数量
- 多线程
我想这些选项取决于您如何使用数据:
- 写入文件时存储 csv 文件的尺寸(在第一行或附加文件中)
- 使用更有效的方式来计算行数 - 也许 http://docs.oracle.com/javase/6/docs/api/java/io/LineNumberReader.html
- 不要创建固定大小的数组(假设这就是您需要行数的原因),而是使用数组列表 - 这可能更有效也可能不会更有效,具体取决于文件的大小。
您的方法不适用于多行值(您将获得无效的行数)和可能恰好包含分隔符的引用值(您将获得无效的列数)。
您应该使用 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 许可证)。
我在这里找到了这个简短但有趣的解决方案:
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"))));
}
}