- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
有一个 6.53 GiB 的大文本文件。它的每一行都可以是数据行或注释行。注释行通常很短,少于 80 个字符,而数据行包含超过 200 万个字符并且是可变长度的。
考虑到每个数据行都需要作为一个单元来处理,有没有一种简单的方法可以在 C++ 中安全快速地读取行?
safe(可变长度数据线安全):该解决方案与std::getline()
一样易于使用.由于长度在变化,希望避免额外的内存管理。
快:解决方案最快可达readline()
在 python 3.6.0
, 甚至和 fgets()
一样快的 stdio.h
.
欢迎使用纯 C 解决方案。在 C 和 C++ 中都提供了用于进一步处理的接口(interface)。
更新 1:感谢来自 Basile Starynkevitch 的简短但宝贵的评论,完美的解决方案来了: POSIX getline()
.由于进一步的处理只涉及从字符到数字的转换,并没有使用字符串类的许多特性,因此在这个应用程序中一个字符数组就足够了。
更新 2:感谢来自 Zulan 的评论和 Galik ,他们都报告了 std::getline()
中的可比性能, fgets()
和 POSIX getline()
,另一种可能的解决方案是使用更好的标准库实现,例如 libstdc++
.此外,这里有一个 report声称 std::getline
的 Visual C++ 和 libc++ 实现没有很好地优化。
从 libc++
移动至 libstdc++
改变了很多结果。在不同平台上使用 libstdc++ 3.4.13/Linux 2.6.32,POSIX getline()
, std::getline()
和 fgets()
显示可比较的性能。一开始,代码在 Xcode 8.3.2 (8E2002) 的默认 clang 设置下运行,因此 libc++
被使用。
更多细节和一些努力(很长):
getline()
的 <string>
可以处理任意长行但有点慢。 readline()
在 C++ 中是否有替代方案?在 python 中?
// benchmark on Mac OS X with libc++ and SSD:
readline() of python ~550 MiB/s
fgets() of stdio.h, -O0 / -O2 ~1100 MiB/s
getline() of string, -O0 ~27 MiB/s
getline() of string, -O2 ~150 MiB/s
getline() of string + stack buffer, -O2 ~150 MiB/s
getline() of ifstream, -O0 / -O2 ~240 MiB/s
read() of ifstream, -O2 ~340 MiB/s
wc -l ~670 MiB/s
cat data.txt | ./read-cin-unsync ~20 MiB/s
getline() of stdio.h (POSIX.1-2008), -O0 ~1300 MiB/s
速度非常粗略地四舍五入,只是为了显示幅度,所有代码块都运行了几次以确保这些值具有代表性。
'-O0/-O2' 表示两种优化级别的速度非常相似
代码如下所示。
readline()
of python
# readline.py
import time
import os
t_start = time.perf_counter()
fname = 'data.txt'
fin = open(fname, 'rt')
count = 0
while True:
l = fin.readline()
length = len(l)
if length == 0: # EOF
break
if length > 80: # data line
count += 1
fin.close()
t_end = time.perf_counter()
time = t_end - t_start
fsize = os.path.getsize(fname)/1024/1024 # file size in MiB
print("speed: %d MiB/s" %(fsize/time))
print("reads %d data lines" %count)
# run as `python readline.py` with python 3.6.0
fgets()
ofstdio.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main(int argc, char* argv[]){
clock_t t_start = clock();
if(argc != 2) {
fprintf(stderr, "needs one input argument\n");
return EXIT_FAILURE;
}
FILE* fp = fopen(argv[1], "r");
if(fp == NULL) {
perror("Failed to open file");
return EXIT_FAILURE;
}
// maximum length of lines, determined previously by python
const int SIZE = 1024*1024*3;
char line[SIZE];
int count = 0;
while(fgets(line, SIZE, fp) == line) {
if(strlen(line) > 80) {
count += 1;
}
}
clock_t t_end = clock();
const double fsize = 6685; // file size in MiB
double time = (t_end-t_start) / (double)CLOCKS_PER_SEC;
fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
fprintf(stdout, "reads %d data lines\n", count);
return EXIT_SUCCESS;
}
getline()
of<string>
// readline-string-getline.cpp
#include <string>
#include <fstream>
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main(int argc, char* argv[]) {
clock_t t_start = clock();
if(argc != 2) {
fprintf(stderr, "needs one input argument\n");
return EXIT_FAILURE;
}
// manually set the buffer on stack
const int BUFFERSIZE = 1024*1024*3; // stack on my platform is 8 MiB
char buffer[BUFFERSIZE];
ifstream fin;
fin.rdbuf()->pubsetbuf(buffer, BUFFERSIZE);
fin.open(argv[1]);
// default buffer setting
// ifstream fin(argv[1]);
if(!fin) {
perror("Failed to open file");
return EXIT_FAILURE;
}
// maximum length of lines, determined previously by python
const int SIZE = 1024*1024*3;
string line;
line.reserve(SIZE);
int count = 0;
while(getline(fin, line)) {
if(line.size() > 80) {
count += 1;
}
}
clock_t t_end = clock();
const double fsize = 6685; // file size in MiB
double time = (t_end-t_start) / (double)CLOCKS_PER_SEC;
fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
fprintf(stdout, "reads %d data lines\n", count);
return EXIT_SUCCESS;
}
getline()
ofifstream
// readline-ifstream-getline.cpp
#include <fstream>
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main(int argc, char* argv[]) {
clock_t t_start = clock();
if(argc != 2) {
fprintf(stderr, "needs one input argument\n");
return EXIT_FAILURE;
}
ifstream fin(argv[1]);
if(!fin) {
perror("Failed to open file");
return EXIT_FAILURE;
}
// maximum length of lines, determined previously by python
const int SIZE = 1024*1024*3;
char line[SIZE];
int count = 0;
while(fin.getline(line, SIZE)) {
if(strlen(line) > 80) {
count += 1;
}
}
clock_t t_end = clock();
const double fsize = 6685; // file size in MiB
double time = (t_end-t_start) / (double)CLOCKS_PER_SEC;
fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
fprintf(stdout, "reads %d data lines\n", count);
return EXIT_SUCCESS;
}
read()
ofifstream
// seq-read-bin.cpp
// sequentially read the file to see the speed upper bound of
// ifstream
#include <iostream>
#include <fstream>
#include <ctime>
using namespace std;
int main(int argc, char* argv[]) {
clock_t t_start = clock();
if(argc != 2) {
fprintf(stderr, "needs one input argument\n");
return EXIT_FAILURE;
}
ifstream fin(argv[1], ios::binary);
const int SIZE = 1024*1024*3;
char str[SIZE];
while(fin) {
fin.read(str,SIZE);
}
clock_t t_end = clock();
double time = (t_end-t_start) / (double)CLOCKS_PER_SEC;
const double fsize = 6685; // file size in MiB
fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
return EXIT_SUCCESS;
}
use
cat
, then read fromcin
withcin.sync_with_stdio(false)
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
int main(void) {
clock_t t_start = clock();
string input_line;
cin.sync_with_stdio(false);
while(cin) {
getline(cin, input_line);
}
double time = (clock() - t_start) / (double)CLOCKS_PER_SEC;
const double fsize = 6685; // file size in MiB
fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
return EXIT_SUCCESS;
}
POSIX getline()
// readline-c-getline.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(int argc, char *argv[]) {
clock_t t_start = clock();
char *line = NULL;
size_t len = 0;
ssize_t nread;
if (argc != 2) {
fprintf(stderr, "Usage: %s <file>\n", argv[1]);
exit(EXIT_FAILURE);
}
FILE *stream = fopen(argv[1], "r");
if (stream == NULL) {
perror("fopen");
exit(EXIT_FAILURE);
}
int length = -1;
int count = 0;
while ((nread = getline(&line, &len, stream)) != -1) {
if (nread > 80) {
count += 1;
}
}
free(line);
fclose(stream);
double time = (clock() - t_start) / (double)CLOCKS_PER_SEC;
const double fsize = 6685; // file size in MiB
fprintf(stdout, "takes %.2f s\n", time);
fprintf(stdout, "speed: %d MiB/s\n", (int)(fsize/time));
fprintf(stdout, "reads %d data lines.\n", count);
// fprintf(stdout, "length of MSA: %d\n", length-1);
exit(EXIT_SUCCESS);
}
最佳答案
嗯,C 标准库是 C++ 标准库的一个子集。来自 C++ 2014 标准的 n4296 草案:
17.2 The C standard library [library.c]
The C++ standard library also makes available the facilities of the C standard library, suitably adjusted toensure static type safety.
因此,如果您在评论中解释性能瓶颈需要它,那么在 C++ 程序中使用 fgets
是完全没问题的 - 只是您应该小心地将它封装在实用程序类中,以便保留面向对象的高级结构。
关于c++ - 如何在 C++ 中快速安全地从文本文件中读取超长行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44241289/
猫f1.txt阿曼维沙尔阿杰贾伊维杰拉胡尔曼尼什肖比特批评塔夫林现在输出应该符合上面给定的条件 最佳答案 您可以在文件读取循环中设置一个计数器并打印它, 计数=0 读取行时做 让我们数一数++ if
我正在尝试查找文件 1 和文件 2 中的共同行。如果公共(public)行存在,我想写入文件 2 中的行,否则打印文件 1 中的非公共(public)行。fin1 和 fin2 是这里的文件句柄。它读
我有这个 SQL 脚本: CREATE TABLE `table_1` ( `IDTable_1` int(11) NOT NULL, PRIMARY KEY (`IDTable_1`) );
我有 512 行要插入到数据库中。我想知道提交多个插入内容是否比提交一个大插入内容有任何优势。例如 1x 512 行插入 -- INSERT INTO mydb.mytable (id, phonen
如何从用户中选择user_id,SUB(row, row - 1),其中user_id=@userid我的表用户,id 为 1、3、4、10、11、23...(不是++) --id---------u
我曾尝试四处寻找解决此问题的最佳方法,但我找不到此类问题的任何先前示例。 我正在构建一个基于超本地化的互联网购物中心,该区域分为大约 3000 个区域。每个区域包含大约 300 个项目。它们是相似的项
preg_match('|phpVersion = (.*)\n|',$wampConfFileContents,$result); $phpVersion = str_replace('"','',
我正在尝试创建一个正则表达式,使用“搜索并替换全部”删除 200 个 txt 文件的第一行和最后 10 行 我尝试 (\s*^(\h*\S.*)){10} 删除包含的前 10 行空白,但效果不佳。 最
下面的代码从数据库中获取我需要的信息,但没有打印出所有信息。首先,我知道它从表中获取了所有正确的信息,因为我已经在 sql Developer 中尝试过查询。 public static void m
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我试图在两个表中插入记录,但出现异常。您能帮我解决这个问题吗? 首先我尝试了下面的代码。 await _testRepository.InsertAsync(test); await _xyzRepo
这个基本的 bootstrap CSS 显示 1 行 4 列: Text Text Text
如果我想从表中检索前 10 行,我将使用以下代码: SELECT * FROM Persons LIMIT 10 我想知道的是如何检索前 10 个结果之后的 10 个结果。 如果我在下面执行这段代码,
今天我开始使用 JexcelApi 并遇到了这个:当您尝试从特定位置获取元素时,不是像您通常期望的那样使用sheet.getCell(row,col),而是使用sheet.getCell(col,ro
我正在尝试在我的网站上开发一个用户个人资料系统,其中包含用户之前发布的 3 个帖子。我可以让它选择前 3 条记录,但它只会显示其中一条。我是不是因为凌晨 2 点就想编码而变得愚蠢? query($q)
我在互联网上寻找答案,但找不到任何答案。 (我可能问错了?)我有一个看起来像这样的表: 我一直在使用查询: SELECT title, date, SUM(money) FROM payments W
我有以下查询,我想从数据库中获取 100 个项目,但 host_id 多次出现在 urls 表中,我想每个 host_id 从该表中最多获取 10 个唯一行。 select * from urls j
我的数据库表中有超过 500 行具有特定日期。 查询特定日期的行。 select * from msgtable where cdate='18/07/2012' 这将返回 500 行。 如何逐行查询
我想使用 sed 从某一行开始打印 n 行、跳过 n 行、打印 n 行等,直到文本文件结束。例如在第 4 行声明,打印 5-9,跳过 10-14,打印 15-19 等 来自文件 1 2 3 4 5 6
我目前正在执行验证过程来检查用户的旧密码,但问题是我无法理解为什么我的查询返回零行,而预期它有 1 行。另一件事是,即使我不将密码文本转换为 md5,哈希密码仍然得到正确的答案,但我不知道为什么会发生
我是一名优秀的程序员,十分优秀!