C ++ ifstream.getline () значительно медленнее, чем Java BufferedReader.readLine ()? - PullRequest
4 голосов
/ 25 июля 2011

Я переписываю одно из моих приложений для Android, чтобы использовать преимущества NDK, и первое, что он должен делать каждый раз, это открывать текстовый файл размером 1,5 МБ (примерно 150 тыс. Строк) и вставлять каждую строку в структуре данных. Когда я сделал эту операцию, используя 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 ++? Спасибо.

Ответы [ 3 ]

12 голосов
/ 25 июля 2011

Одна мысль о том, что синхронизация stdio может замедлить вас.Это можно отключить.Я не знаю, объяснит ли это все различия, но вы можете попробовать.Кроме того, вы не используете eof() правильно.Наконец, я бы использовал std :: string версию getline()

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

. Я не тестировал этот код, но вы можете попробовать его и посмотреть, будет ли он иметь значение.

3 голосов
/ 25 июля 2011

Возможно ли, что поток не буферизован, и он делает доступ к SD для каждого байта данных? Чтобы обеспечить буфер, выполните следующие действия (размер, который вы считаете нужным).

ifstream ifs;
char stream_buffer[4096];
ifs.rdbuf()->pubsetbuf(stream_buffer, sizeof(stream_buffer) );
ifs.open(argv[1]);
0 голосов
/ 26 июля 2011

C ++ не буферизует потоки для вас (отредактируйте: они не будут по умолчанию , см. Решение Дэйва Смита).Я скажу вам, что ваш код будет работать медленно на обычном диске.У меня нет большого опыта работы с 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;
    }
}

Это нигде не работает, так что никаких гарантий помимо тестированиявот видите;)

...