2017-02-24 36 views
0

テキストファイルにデータを追加しようとしています。しかし、私は何らかの理由でそれがガベージデータを生成するのを見る。また、正しいデータを1回入力しますが、それに続いてガベージデータが表示されます。C++がファイルにガベージデータを書き込む

void TextFileLogger::log(std::string msg){ 
     using namespace std; 
     //ofstream output_file("students.data", ios::binary); 
     std::ofstream logFile; 
     // creating, opening and writing/appending data to a file 
     char filename[] = "log.txt"; 
     logFile.open(filename, ios::binary | ios::app |ios::out); 

     if (logFile.fail()) 
     { 
      std::cout << "The " << filename << " file could not be created/opened!" << std::endl; 
      // 0-normal, non zero - some errors 
     } 
     else 
     { 
      if (!logFile.write((char*)&msg, sizeof(msg))) 
      { 
       cout << "Could not write file" << endl; 
      } 
      else 
      { 
       streamsize bytesWritten = logFile.tellp(); 
       if (bytesWritten != sizeof(msg)) 
       { 
        cout << "Could not write expected number of bytes" << endl; 
       } 
       else 
       { 
        logFile << msg << std::endl; 
        cout << "file written OK" << endl; 
       } 
      } 
     } 

    } 
+0

これはファイルが存在しない場合にも発生しますか? –

答えて

2

それは楽しいです!

(char*)&msgあなたが期待することはありません:std::stringは、主に、実際のデータを含む動的に割り当てられたバッファへのポインタです。 std::stringのアドレスを取得して内部の情報を読み取ろうとすると、データではなく内部のビューが表示されます。ここでC++ static_castを使用すると、変換が意味をなさないと伝えることで問題を回避できます。 sizeof(msg)は同様に、データの長さではなくstd::stringのサイズを返します。

したがって、あなたのソリューションは:msg.data()msg.size()を使用してください。これはまさにそのためのものです。

なぜ...(時には)あなたの文字列とゴミの束を出力するのですか?まあ、std::stringは通常、SSO(Small String Optimization)を使用します。 std::stringには実際には小さなバッファが含まれ、動的割り当てなしで十分に短い文字列を格納します。 std::stringオブジェクト全体を調べると、このバッファが渡されます。

+0

ありがとう、とても助かりました! –

1

内部的に含まれるすべてのメンバー変数を使用して、std :: stringオブジェクト全体の内容を記述しています。 次のいずれかが必要:

logFile.write(msg.c_str(), msg.length()); 

そして、私は疑問に思う:

logFile << msg; 

またはあなたが本当にwrite()を使用したい場合は、なぜ作成/バイナリモードでファイルを開くか、あなたはその後の文字列を書くとき?
最後に、最後のelse節に2回目のデータを書きます。

1

msg.size()と交換すると、sizeof()はあなたの考えをしていません!

また、(char*)&msgは何も考えません。代わりにmsg.data()を使用してください。ofstreamのがのstd ::文字列をオペレータ< <が上書きされますので、より良いとしても

logFile.write(msg.data(), msg.size()); 

または、::

logFile.write((char*)&msg, sizeof(msg)); 

はに書き換えるべき

logfile << msg; 
1

問題は、この行を次のとおりです。

if (!logFile.write((char*)&msg, sizeof(msg))) 

それはこのようになります。あなたが関数にのstd ::文字列を渡しているので、あなたが機能を活用する必要があり、それは(c_str()長さ()を提供

if (!logFile.write(msg.c_str(), msg.length())) 

)これをchar *にキャストしようとする代わりに(これはいつも乱雑になりますが、あなたはconstをキャストしています。

1

この:

if (!logFile.write((char*)&msg, sizeof(msg))) 

は非常に多くの方法で間違っています。 msgはcharの配列ではありません。これはstd :: stringです。キャストを使用してコンパイラに向かっているのは、常に悪いことです。文字列のサイズはではなく、に含まれている文字のサイズです。なぜあなたはobviosを使用していないのですか: