我正在使用C ++,ifstream
和文本文件。我正在寻找每行结尾的位置,因为我需要从行尾读取n
个字符。
目前,我正在读取每个字节并测试它是否与Unix换行符(LF)相对应。
不幸的是,输入通常是长文本,我的方法也不快。
有没有更快的方法?
答案 0 :(得分:6)
如果您正在寻找原始速度,我会将内存映射到文件并使用strchr
之类的内容来查找换行符;
p = strchr(line_start, '\n');
然后只要p
不是NULL
或内存区域中的第一个字符,就可以使用p[-1]
在换行符之前读取字符。
注意:如果文件可能包含'\0'
个字符,那么您应该使用memchr
。实际上,这可能是合乎需要的,因为它允许您指定缓冲区的大小(内存区域)。
答案 1 :(得分:2)
我正在使用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";
}
答案 2 :(得分:1)
您可以查看std::string
中的getline功能。尝试一次读取整行,然后从字符串末尾读取字符。
与性能问题一样,真正的诀窍是通过分析器运行代码以查看它花费时间的位置。 “最快”和“足够快”之间通常存在非常明显的区别。
答案 3 :(得分:1)
没有更简单的方法可以到达行标记的末尾,但是通过存储读取数据时读取的内容可以节省一些时间。你不需要回去,你的循环会非常快。
创建一个大小为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;
}
答案 4 :(得分:0)
快速&amp;肮脏的方式是这样的:
ifs.seekg( 0, std::ifstream::end );
std::string buffer( ifs.tellg(), '\0' );
ifs.seekg( 0, std::ifstream::beg );
ifs.read( &buffer[0], buffer.size() );
然后在缓冲区上工作。这可能会为您提供所需的全部速度(根据我的经验,可以达到许多数量级)。如果你想能够处理任意大的文件,你需要稍微修改一下逻辑(而不是用块搜索)。
答案 5 :(得分:0)
无论你做什么,你仍然最终会通过文件线性搜索 。您可能搜索速度更快,但仍然是线性搜索。
真正的解决方案是更改文件的格式,因此在文件开头附近写入“有趣”字符的索引。到了阅读它的时候,你可以完全跳过文件的“无趣”部分。
如果不可能,您可以生成单独的“索引”文件。这不会使您无需执行一次线性搜索,但可以避免在同一文件上重复执行此操作。这当然只有在你不止一次处理同一个文件时才有意义。
顺便说一句,即使是线性扫描也应该非常快。你应该比任何东西都更受I / O限制。您的文件有多大,“我的方法不快”是什么意思?