我正在使用 C++、.ifstream
和文本文件。我正在寻找每行末尾的位置,因为我需要n
从行尾读取字符。
目前,我正在读取每个字节并测试它是否对应于 Unix 换行符 (LF)。
不幸的是,输入通常是长文本,我的方法并不快。
有没有更快的方法?
我正在使用 C++、.ifstream
和文本文件。我正在寻找每行末尾的位置,因为我需要n
从行尾读取字符。
目前,我正在读取每个字节并测试它是否对应于 Unix 换行符 (LF)。
不幸的是,输入通常是长文本,我的方法并不快。
有没有更快的方法?
如果您正在寻找原始速度,我会内存映射文件并使用类似strchr
的东西来查找换行符;
p = strchr(line_start, '\n');
那么只要p
不是NULL
内存区域中的第一个字符,您就可以使用p[-1]
读取换行符之前的字符。
注意:如果文件可能包含'\0'
字符,那么您应该使用memchr
. 事实上,这可能是可取的,因为它允许您指定缓冲区(内存区域)的大小。
我正在使用 C++、ifstream 和文本文件。我正在寻找每行末尾的位置,因为我需要从行尾读取 n 个字符。
我将专注于您的要求,从行尾读取“n”个字符,而不是您的问题:
// Untested.
std::string s;
while(std::getline(std::cin, s)) {
if(s.size() > n) s.erase(s.begin(), s.end()-n);
// s is the last 'n' chars of the line
std::cout << "Last N chars: " << s << "\n";
}
您可以查看. std::string
尝试一次读取整行,然后从字符串末尾读取字符。
与通常的性能问题一样,真正的诀窍是通过分析器运行您的代码,以查看它在哪里花费时间。“最快”和“足够快”之间通常存在非常真实的区别。
没有更简单的方法可以到达行标记的末尾,但是您可以通过在读取数据时存储所读取的内容来节省一些时间。你不需要回去,你的循环会非常快。
创建一个大小为 的字符数组n
,并将其用作循环缓冲区:当您到达数组末尾时,只需绕回其开头即可。将字符存储在循环缓冲区的下一个位置。
当您检测到 时'\n'
,您的缓冲区包含n
前面的字符,只是稍微有点乱:前缀从缓冲区指针开始并到达缓冲区的末尾,而后缀从零开始并到达缓冲区指针减一。
这是一个如何使其工作的示例(假设n
== 20):
int main()
{
ifstream fs("c:\\temp\\a.txt");
char buf[20];
int bp = 0;
bool circular = false;
while (fs.good()) {
char ch = fs.get();
if (ch != '\n') {
buf[bp] = ch;
bp = (bp+1) % 20;
circular |= !bp;
} else {
string s;
if (circular) {
s = string(buf+bp, buf+20) + string(buf, buf+bp);
} else {
s = string(buf, buf+bp);
}
cerr << s << endl;
circular = false;
bp = 0;
}
}
return 0;
}
快速而肮脏的方式是这样的:
ifs.seekg( 0, std::ifstream::end );
std::string buffer( ifs.tellg(), '\0' );
ifs.seekg( 0, std::ifstream::beg );
ifs.read( &buffer[0], buffer.size() );
然后改为使用缓冲区。这可能会让您获得所需的所有加速(根据我的经验,很多数量级)。如果您希望能够处理任意大的文件,则需要稍微修改逻辑(改为搜索块)。
不管你做什么,你最终还是会线性搜索文件。您可能会更快地搜索,但它仍然是线性搜索。
真正的解决方案是改变文件的格式,所以“有趣”字符的索引写在文件开头附近。当需要阅读它时,您可以完全跳过文件中“无趣”的部分。
如果这不可能,您也许可以生成一个单独的“索引”文件。这不会让您不必执行一次线性搜索,但可以让您不必在同一个文件上重复执行此操作。这当然只有在您要多次处理同一个文件时才重要。
顺便说一句,即使是线性扫描也应该很快。你应该更受 I/O 约束。您的文件有多大,“我的方法不快”是什么意思?