将文件读取为缓冲区,并避免在读取之间分裂线
Reading file into buffer and avoiding splitting lines between reads
我正在阅读Sehe在C 中快速文件阅读的答案,看起来像这样。
static uintmax_t wc(char const *fname)
{
static const auto BUFFER_SIZE = 16*1024;
int fd = open(fname, O_RDONLY);
if(fd == -1)
handle_error("open");
/* Advise the kernel of our access pattern. */
posix_fadvise(fd, 0, 0, 1); // FDADVICE_SEQUENTIAL
char buf[BUFFER_SIZE + 1];
uintmax_t lines = 0;
while(size_t bytes_read = read(fd, buf, BUFFER_SIZE))
{
if(bytes_read == (size_t)-1)
handle_error("read failed");
if (!bytes_read)
break;
for(char *p = buf; (p = (char*) memchr(p, 'n', (buf + bytes_read) - p)); ++p)
++lines;
}
return lines;
}
这很酷,但是我想知道,当我们不处理类似的角色操作时,是否可以采用类似的方法,而是想在每条数据行上操作。例如,我有一个双打文件,并且已经在每行上使用了一些函数parse_line_to_double
。
12.44243
4242.910
...
也就是说,如何在缓冲区中读取BUFFER_SIZE
字节,但要避免将最后一行读取?有效地,我可以问"给我BUFFER_SIZE
或更少的字节,同时确保最后一个字节读取为newline字符(或eof)"?
对低水平IO的了解很少,想到的想法是
- 我可以将
fd
"备份"到迭代之间的最新新线? - 我是否必须保留第二个缓冲区,持有当前行的副本?
这是一个比较测试。首先,让我们尝试简单的方法。只需使用标准C 函数读取文件:
#include <iostream>
#include <string>
#include <fstream> //std::ifstream
#include <sstream> //std::stringstream
uintmax_t test1(char const *fname)
{
std::ifstream fin(fname);
if(!fin) return 0;
uintmax_t lines = 0;
std::string str;
double value;
while(fin >> value)
{
//std::cout << value << "n";
lines++;
}
return lines;
}
接下来,使用std::stringstream
,这快的速度约为2.5倍:
uintmax_t test2(char const *fname)
{
std::ifstream fin(fname);
if(!fin) return 0;
uintmax_t lines = 0;
std::string str;
double value;
std::stringstream ss;
ss << fin.rdbuf();
while(ss >> value)
lines++;
return lines;
}
接下来,让我们读取整个文件到内存。只要文件小于1 GIB左右,这将是可以的。假设每行上有double
值,则可以提取该值。test3
更复杂且灵活较低,并且不比test2
快:
uintmax_t test3(char const *fname)
{
std::ifstream fin(fname, std::ios::binary);
if(!fin) return 0;
fin.seekg(0, std::ios::end);
size_t filesize = (size_t)fin.tellg();
fin.seekg(0);
std::string str(filesize, 0);
fin.read(&str[0], filesize);
double value;
uintmax_t lines = 0;
size_t beg = 0;
size_t i;
size_t len = str.size();
for(i = 0; i < len; i++)
{
if(str[i] == 'n' || i == len - 1)
{
try
{
value = std::stod(str.substr(beg, i - beg));
//std::cout << value << "n";
beg = i + 1;
lines++;
}
catch(...)
{
}
}
}
return lines;
}
要与问题中的wc
函数进行比较,让我们将整个文件读取到内存中,只计算行数。这比wc
(如预期)快一点,这表明不需要其他优化
uintmax_t test_countlines(char const *fname)
{
std::ifstream fin(fname, std::ios::binary);
if(!fin) return 0;
fin.seekg(0, std::ios::end);
size_t filesize = (size_t)fin.tellg();
fin.seekg(0);
std::string str(filesize, 0);
fin.read(&str[0], filesize);
uintmax_t lines = 0;
for(auto &c : str)
if(c == 'n')
lines++;
return lines;
}
相关文章:
- ifstream 尝试读取 9 到 13 之间的无符号字符时非常奇怪的行为
- 读取USB与操作系统、C++之间传输的数据
- 为什么我的 cout 一次执行,尽管 cin 应该在两者之间读取?
- 如何读取特定单词之间的文本文件?
- 尝试从每个预期数据之间有多个空间的文件中读取和存储数据
- c++ 从大型数组中读取 3D 坐标并计算它们之间的距离
- 如何从.txt文件中读取多个2D数组,而无需每个之间的新线
- 嵌入式串行读取操作和桌面PC之间可能有什么区别
- 将文件读取为缓冲区,并避免在读取之间分裂线
- 在C++中,如何在并发读取和锁定的单线程写入uncodered_map之间进行交替
- 数据类型类和读取器/解析器之间的耦合
- 在使用pthread_create创建的线程之间读取和写入管道时,是否需要关闭 fds
- 使用 WinAPI/C++ 在 Windows 上的进程之间进行多读取器、单写入器同步锁定
- 运算符 [] 重载写入/读取之间的区别
- 在 TheADS 中的向量读取之间插入元素
- 在编译器之间读取和写入原始对象到磁盘(istream)
- 在线程之间发送和读取字符串
- C程序读取两个字符串之间的数据
- 需要读取文本文件中某些字符之间的文本
- 实现有界缓冲区(读取器和写入器之间无块,读取器之间有块,写入器之间有块)