2008-11-15 7 views
2

J'implémente une base de données de fichiers très simple. J'ai 2 opérations de base:La lecture C++ à partir d'un fichier bloque toute autre écriture. Pourquoi?

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; 
}  

la classe a m_fileStream et m_fileName en tant que membres privés.

OK - voici le problème:

Si je fais quelque chose comme:

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

Le résultat final est que le fichier contiendra que "a"; POURQUOI?

REMARQUE: il semble que getline() définira le bit de défaillance. mais pourquoi?

Répondre

4

changement

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

    } 

à

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

Sinon, vous obtiendrez une ligne vide supplémentaire à la fin. eof() retournera vrai seulement une fois que vous avez essayé de lire passé la fin du fichier, et pas si seulement la lecture suivante serait après la fin du fichier.

Il définit failbit car getline essaie d'extraire les caractères du flux. S'il n'y a pas de caractères à gauche (et aucun '\n' n'a encore été vu), stream.get(c) à un caractère définira le failbit. Ensuite, getline définira eofbit, puis .eof() retournera vrai, et votre boucle se termine.

Si vous ne voulez pas, définissez votre condition de !stream.eof() à stream.peek() != EOF (et assurez-vous qu'il y a une nouvelle ligne de fin dans votre fichier).

Ceci est maintenant aussi la solution à votre problème: .close() ne pas .clear() votre flux, de sorte que le failbit est toujours défini si vous rouvrez votre fichier. appelez stream.clear() après avoir lu vos affaires, puis cela fonctionne.

+0

Non, cela ne fonctionne pas. Le flux est toujours dans un état d'échec (le bit d'échec est défini). –

+0

Le code que vous nous avez montré fonctionne (avec cette correction). Donc c'est quelque chose que vous ne nous montrez pas qui échoue. getline() définira finalement l'indicateur eof() et ainsi fail() ne sera pas vrai. Mais fermer le fichier le rendra muet. –

+0

Martin: De quoi parlez-vous? Pouvez-vous s'il vous plait reformuler? À l'heure actuelle, cela n'a guère de sens. –

1

Je pense que litb à peu près cloué. Mais juste pour ajouter mon 0,02 $:

1) Je toujours privilégié:

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

Comme [mauvais] événements autres que EOF peut se produire.

(Et, comme mentionné par litb, coup d'oeil()! = EOF contourne le problème du flux ne pas fixer EOF jusqu'à ce que nous essayons de lire après la fin.)

.

2) Depuis « m_fileStream » est open'ed, lecture/écrit/rincée, et fermé dans ces deux méthodes ...

Pourquoi ne pas déclarer localement sur la pile? Cela garantit qu'aucun problème d'état antérieur ne subsiste pour vous déranger. Et si vous accédez au disque, l'efficacité n'est peut-être pas la plus grande préoccupation ...

De plus, vous pouvez être paresseux:

ifstream stream (m_fileName.c_str()); 
ASSERT(stream, !=, NULL); // Uses my own ASSERT macro && stream.operator(). 
while (stream && (stream.peek() != EOF)) {...} 
Questions connexes