C ++ чтение из файла блокирует дальнейшую запись. Зачем? - PullRequest
2 голосов
/ 15 ноября 2008

Я реализую очень простую файловую базу данных. У меня есть 2 основные операции:

void Insert(const std::string & i_record)
{
   //create or append to the file
    m_fileStream.open(m_fileName.c_str(), std::ios::out | std::ios::app);

    if (m_fileStream.is_open())
    {
        m_fileStream << i_record << "\n";
    }

    m_fileStream.flush();
    m_fileStream.close();
}

/*
* Returns a list with all the items in the file.
*/
 std::vector<std::string> SelectAll()
 {
    std::vector<std::string> results;

    m_fileStream.open(m_fileName.c_str(), std::ios::in);

    std::string line;
    if (m_fileStream.is_open())
    {
        while (!m_fileStream.eof())
        {
            getline (m_fileStream, line);
            results.push_back(line);

        }
    }

    m_fileStream.close();

    return results;
 }    

класс имеет m_fileStream и m_fileName в качестве закрытых членов.

ОК - вот проблема:

Если я сделаю что-то вроде:

db->Insert("a");
db->SelectAll();
db->Insert("b");

Конечным результатом является то, что файл будет содержать only"a"; ЗАЧЕМ?

ПРИМЕЧАНИЕ: похоже, что getline () установит бит сбоя. но почему?

Ответы [ 2 ]

4 голосов
/ 15 ноября 2008

Изменение

    while (!m_fileStream.eof())
    {
        getline (m_fileStream, line);
        results.push_back(line);

    }

до

    while (getline (m_fileStream, line))
    {
        results.push_back(line);
    }

В противном случае вы получите еще одну пустую строку в конце. eof() вернет true только после того, как вы попытались прочитать после конца файла, и не , если только следующее чтение будет после конца файла.

Устанавливает failbit, потому что getline пытается извлечь символы из потока. Если не осталось символов (а '\n' еще не было видно), stream.get(c) для символа установит failbit. Тогда getline установит eofbit, а затем .eof() вернет true, и ваш цикл завершится.

Если вы не хотите устанавливать failbit, измените ваше условие с !stream.eof() на stream.peek() != EOF (и убедитесь, что в вашем файле есть завершающий символ новой строки).

Теперь это также решение вашей проблемы: .close() не .clear() ваш поток, поэтому failbit все еще устанавливается, если вы снова открываете свой файл. позвоните stream.clear() после прочтения вашего материала, и тогда все заработает.

1 голос
/ 15 ноября 2008

Я думаю, что LITB в значительной степени прибил его. Но только чтобы добавить мои 0,02 доллара:

1) Я всегда отдавал предпочтение:

while ( stream && (stream.peek() != EOF) )  {...}

Поскольку [плохие] события могут отличаться от EOF.

(И, как уже упоминалось в litb, peek ()! = EOF решает проблему, когда поток не устанавливает EOF, пока мы не попытаемся прочитать до конца.)

.

2) Поскольку "m_fileStream" открыт, прочитан / записан / очищен и закрыт в обоих этих методах ...

Почему бы не объявить это локально в стеке? Это гарантирует, что не осталось никаких предыдущих проблем, которые могли бы вас испортить. И если вы обращаетесь к диску, эффективность может быть не самой большой проблемой ...

Кроме того, вы можете быть ленивым:

ifstream stream ( m_fileName.c_str() );
ASSERT( stream, !=, NULL );  // Uses my own ASSERT macro && stream.operator().
while ( stream && (stream.peek() != EOF) )  {...}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...