【问题标题】:C++ ifstream.getline() significantly slower than Java's BufferedReader.readLine()?C++ ifstream.getline() 明显慢于 Java 的 BufferedReader.readLine()?
【发布时间】:2011-07-25 18:41:34
【问题描述】:

我正在重写我的一个 Android 应用程序以利用 NDK,它每次要做的第一件事就是打开一个 1.5MB 的文本文件(大约 150k 行)并将每一行在数据结构中。当我使用 Java 的 BufferedReader.readLine() 执行此操作时,从 SD 卡读取文件需要大约 2.5 秒。这是我用于此的代码:

try {
    BufferedReader br = new BufferedReader(new FileReader("/sdcard/testfile.txt"));
    String thisLine;
    while ((thisLine = br.readLine()) != null) {
        Log.d(TAG, thisLine);
    }
} catch (IOException e) {
    //Log error
}

将 C++ 与 ifstream 一起使用需要更长的时间……对于同一个文件,大约需要 3 分钟。这是我在 C++ 中使用的代码:

char buffer[256];
ifstream ifs;
ifs.open("/sdcard/testfile.txt", ifstream::in);
if (ifs.is_open()) {
    while (!ifs.eof()) {
        ifs.getline (buffer,100);
        LOGD(buffer);
    }
}

我对 C++ 相当生疏,但对于增加的读取时间想不出任何合乎逻辑的解释。有一段时间我认为这可能是 LOGD 功能,但我尝试将其完全去掉,阅读时间并没有太大帮助。有没有人对问题可能有任何想法?有没有更快的方法在 C++ 中逐行读取文件?谢谢。

【问题讨论】:

  • 您的 C++ 代码编译时是否启用了优化?
  • 是的,它是用 -O2 编译的(也试过 -O3)。调试已关闭。
  • ifstream ifs.open(...) 不会编译...
  • 我注意到您标记了这个 android,我不是 android 专家,但 c++ 代码是否可能正在回调“java”代码来执行 I/O 操作?
  • @sth:对不起,我试着从记忆中发布这个。它已在 OP 中修复。

标签: java android c++ java-native-interface android-ndk


【解决方案1】:

一个想法是stdio 同步可能会减慢您的速度。那可以关掉。我不知道这是否会导致所有差异,但您可以尝试。另外,您没有正确使用eof()。最后,我会使用getline()的std::string版本@

std::ios::sync_with_stdio(false);
ifstream ifs("/sdcard/testfile.txt");
std::string line;
while (getline(ifs, line))
{
    LOGD(line);
}

我还没有测试过这段代码,但你可以试试看它是否有所作为。

【讨论】:

  • 感谢您的回复,但这似乎没有什么不同。
  • 说得太早了...这解决了它。它现在读取文件的时间与 Java 版本大致相同。非常感谢!
  • 太好了,我刚刚在我的程序中尝试了ios::sync_with_stdio(false),它加快了 getline 7 倍,感谢您的精彩提示
【解决方案2】:

流是否可能是无缓冲的,并且它正在对每个数据字节进行 SD 访问?要提供缓冲区,请执行以下操作(您认为合适的大小)。

ifstream ifs;
char stream_buffer[4096];
ifs.rdbuf()->pubsetbuf(stream_buffer, sizeof(stream_buffer) );
ifs.open(argv[1]);

【讨论】:

  • 这对我来说听起来很有希望,但似乎没有帮助。还是感谢您的回复!
【解决方案3】:

C++ 不会为您缓冲流(编辑:默认情况下它们不会,请参阅 Dave Smith 的解决方案)。我会告诉你,你的代码在基于普通盘片的磁盘上会很慢。我对android没有太多经验,fwiw。

我通常使用这样的东西:

struct buffered_reader {
    buffered_reader(std::istream &data_) : data(data_), done(false) {}
    bool next(std::string &line) {
        if (!lines.size()) {
            if (done)
                return false;
            std::string line;
            for (size_t i = 0; i < 500; i++) {
                std::getline(data, line);
                if (data.eof()) {
                    done = true;
                    break;
                }
                lines.push_back(line);
            }
        }
        line = lines.front();
        lines.pop_front();
        return true;
    }
    std::istream &data;
    bool done;

    std::deque<std::string> lines;
};

TEST(blah) {
    std::stringstream ss;
    ss << "a" << std::endl;
    ss << "a" << std::endl;
    ss << "a" << std::endl;
    ss << "a" << std::endl;

    buffered_reader reader(ss);
    std::string line;
    while(reader.next(line)) {
        std::cout << line << std::endl;
    }
}

这在任何地方都没有生产,因此除了您在此处看到的测试之外没有任何保证;)

【讨论】:

  • 您说 C++ 不缓冲流,但文档似乎另有说明。似乎所有 ifstream 对象都有一个关联的 filebuf 对象,用于缓冲所有输入。我理解错了吗?谢谢回复。来源:cplusplus.com
  • @Eric 啊,在我的脑海中读到“C++ 不会为您缓冲流默认情况下”并且最后一位丢失了。使用 Dave Smith 的解决方案非常好,我倾向于使用/想要基于行的缓冲。我怀疑摊销时间是等价的。
猜你喜欢
  • 2019-05-29
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-20
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
相关资源
最近更新 更多