0

我正在使用 C++、.ifstream和文本文件。我正在寻找每行末尾的位置,因为我需要n从行尾读取字符。

目前,我正在读取每个字节并测试它是否对应于 Unix 换行符 (LF)。

不幸的是,输入通常是长文本,我的方法并不快。

有没有更快的方法?

4

6 回答 6

6

如果您正在寻找原始速度,我会内存映射文件并使用类似strchr的东西来查找换行符;

p = strchr(line_start, '\n');

那么只要p不是NULL内存区域中的第一个字符,您就可以使用p[-1]读取换行符之前的字符。

注意:如果文件可能包含'\0'字符,那么您应该使用memchr. 事实上,这可能是可取的,因为它允许您指定缓冲区(内存区域)的大小。

于 2012-03-08T16:03:03.953 回答
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";
}
于 2012-03-08T16:25:36.540 回答
1

您可以查看. std::string尝试一次读取整行,然后从字符串末尾读取字符。

与通常的性能问题一样,真正的诀窍是通过分析器运行您的代码,以查看它在哪里花费时间。“最快”和“足够快”之间通常存在非常真实的区别。

于 2012-03-08T16:02:19.407 回答
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;
}
于 2012-03-08T16:11:13.450 回答
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() );

然后改为使用缓冲区。这可能会让您获得所需的所有加速(根据我的经验,很多数量级)。如果您希望能够处理任意大的文件,则需要稍微修改逻辑(改为搜索块)。

于 2012-03-08T16:10:07.180 回答
0

不管你做什么,你最终还是会线性搜索文件。您可能会更快地搜索,但它仍然是线性搜索。

真正的解决方案是改变文件的格式,所以“有趣”字符的索引写在文件开头附近。当需要阅读它时,您可以完全跳过文件中“无趣”的部分。

如果这不可能,您也许可以生成一个单独的“索引”文件。这不会让您不必执行一次线性搜索,但可以让您不必在同一个文件上重复执行此操作。这当然只有在您要多次处理同一个文件时才重要。

顺便说一句,即使是线性扫描也应该很快。你应该更受 I/O 约束。您的文件有多大,“我的方法不快”是什么意思?

于 2012-03-08T16:13:52.400 回答