C ++ fstream: как узнать размер строки при чтении? - PullRequest
2 голосов
/ 10 февраля 2012

... как кто-то может вспомнить, я все еще застрял на C ++ строк.Хорошо, я могу записать строку в файл, используя fstream, следующим образом

outStream.write((char *) s.c_str(), s.size());

Когда я хочу прочитать эту строку, я могу сделать

inStream.read((char *) s.c_str(), s.size());

Все работает, как ожидалось.Проблема заключается в том, что если я изменю длину своей строки после записи в файл и перед повторным чтением, печать этой строки не вернет мне исходную строку, а приведет к более короткой / более длинной.Итак: если мне нужно хранить много строк в файле, как я могу узнать их размер при чтении обратно?

Большое спасибо!

Ответы [ 4 ]

3 голосов
/ 10 февраля 2012

Вы не должны использовать неотформатированные функции ввода / вывода (read() и write()), если вы просто хотите записать обычные читаемые человеком строковые данные.Обычно вы используете эти функции только тогда, когда вам нужно читать и записывать компактные двоичные данные, которые для новичка, вероятно, не нужны.Вместо этого вы можете написать обычные строки текста:

std::string text = "This is some test data.";
{
    std::ofstream file("data.txt");
    file << text << '\n';
}

Затем прочитать их обратно с помощью getline():

{
    std::ifstream file("data.txt");
    std::string line;
    std::getline(file, line);
    // line == text
}

Вы также можете использовать обычный оператор форматирования >> для чтения,но при применении к string он читает токены (непробельные символы, разделенные пробелами), а не целые строки:

{
    std::ifstream file("data.txt");
    std::vector<std::string> words;
    std::string word;
    while (file >> word) {
        words.push_back(word);
    }
    // words == {"This", "is", "some", "test", "data."}
}

Все отформатированные функции ввода-вывода автоматически обрабатывают управление памятьюдля вас, поэтому нет необходимости беспокоиться о длине ваших строк.

1 голос
/ 10 февраля 2012

Хотя ваше решение для записи более или менее приемлемо, ваше решение для чтения в корне ошибочно: оно использует внутреннее хранилище вашей старой строки в качестве буфера символов для вашей новой строки, что очень, очень плохо (мягко говоря).

Вы должны переключиться на форматированный способ чтения и записи потоков, например:

Письмо:

outStream << s;

Чтение:

inStream >> s;

Таким образом, вам вообще не нужно будет определять длину ваших строк.

Этот код отличается тем, что останавливается на пробелах; Вы можете использовать getline, если хотите остановиться только на \n символах.

0 голосов
/ 10 февраля 2012

Если вы хотите использовать неформатированный ввод / вывод, ваши единственные реальные варианты - либо использовать фиксированный размер, либо каким-либо образом предварительно добавлять размер, чтобы вы знали, сколько символов нужно прочитать.В противном случае, при использовании форматированного ввода-вывода это в некоторой степени зависит от того, что содержат ваши строки: если они могут содержать все жизнеспособные символы, вам необходимо реализовать какой-либо механизм цитирования.В простых случаях, когда строки состоят, например, из последовательности без пробелов, вы можете просто использовать отформатированный ввод-вывод и обязательно ставить пробел после каждой строки.Если ваши строки не содержат какой-либо символ, полезный в качестве кавычки, кавычки относительно легко обрабатывать:

std::istream& quote(std::istream& out) {
    char c;
    if (in >> c && c != '"') {
        in.setstate(std::ios_base::failbit;
    }
}

out << '"' << string << "'";
std::getline(in  >> std::ws >> quote, string, '"');

Очевидно, вы можете связать эту функциональность с классом.

0 голосов
/ 10 февраля 2012

Вы можете записать строки и записать дополнительный 0 (нулевой терминатор) в файл.Тогда будет легко разделить строки позже.Кроме того, вы можете читать и писать строки

outfile << string1 << endl;
getline(infile, string2, '\n');
...