我有一个清理文件的过程,然后将它们保存到 arrow
稍后可以读取的格式正确的文件中。这些文件采用 tsv 格式,大约有 30 列,混合数据类型 - 大部分是字符,但也有一些数字列。有大量文件只有标题而没有数据内容。我决定在读入文件进行清理之前,我会检查以确保它们具有内容,而不是作为数据帧读入文件,然后检查内容。所以,本质上,我只是想检查文件中的行数是否为 >= 2
。我正在使用一个简单的 C++ 方法,使用 Rcpp
将其拉入 R
中:
Rcpp::cppFunction(
"
#include <fstream>
bool more_than_one_line(std::string filepath) {
std::ifstream input_file;
input_file.open(filepath);
std::string unused;
int numLines = 0;
while(std::getline(input_file, unused)) {
++numLines;
if (numLines >= 2) {
return true;
}
}
return false;
}
"
)
我进行了一些计时测量,如下所示:
v <- vector(mode="numeric", length=1000)
ii = 0
for (file in listOfFiles[1:1000]) {
print(ii)
ii = ii + 1
t0 <- Sys.time()
more_than_one_line(file);
v[ii] <- difftime(Sys.time(), t0)
}
当我运行此代码时,如果文件以前从未被读取过,则每个文件大约需要 1 秒;如果我在之前处理过的文件上运行代码,速度会快得多。然而,根据 this SO answer ,计算 12M 行文件中的行数的最快时间是 0.1 秒(我的文件最多 500k 行),并且推荐 fastest strategy 的 SO 用户(使用 Linux wc
)还建议使用 C++ 会相当快。我认为我编写的 C++ 方法即使不是更快,也会与 wc
方法一样快,至少是因为我最多只阅读前两行。
我的想法是错误的吗?难道是我的方法不对?
最佳答案
在我对OP链接的问题的回答中,我提到了包fpeek
,函数peek_count_lines
。这是一个用 C++ 编写的快速函数。我的计算机(运行 Windows 11 的 1 年前第 11 代 Intel(R) Core(TM) i5-1135G7 @ 2.40GHz)上有 82 个 CSV 文件的目录,行数从 4.8K 行到 108K 行不等,平均每个文件需要 0.03 秒文件获取行数。
然后,您可以在 flsize >= 2
条件下使用这些值和子集。
#path <- "my/path/omited"
fls <- list.files(path, full.names = TRUE)
# how many files
length(fls)
#> [1] 82
# range of file sizes in MB
range(file.size(fls)) / 1024L / 1024L
#> [1] 0.766923 19.999812
# total file size in MB
sum(file.size(fls)) / 1024L / 1024L
#> [1] 485.6675
# this is the main problem
t0 <- system.time(
flsize <- sapply(fls, fpeek::peek_count_lines)
)
# the files have from 4.8K to 108K lines
range(flsize)
#> [1] 4882 108503
# how many files have more than just the header line
sum(flsize >= 2)
#> [1] 82
# timings
t0
#> user system elapsed
#> 0.28 1.12 2.30
# average timings per file
t0/length(flsize)
#> user system elapsed
#> 0.003414634 0.013658537 0.028048780
创建于 2023-02-04,使用 reprex v2.0.2
关于c++ - 使用 Rcpp 计算文件序列行数的时间量高于预期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75342573/