0

そうですね、以下で説明する 2 つの別々の試みがあるので、ご容赦ください。

私は最初にここ (http://www.cplusplus.com/doc/tutorial/files/) のガイドを読み始めました。ただし、read() の使用方法の良い例と思われるものが含まれていますが、write() の使用方法の例は含まれていません。

最初に、単純な char 配列を write() を使用してバイナリに格納しようとしました。私の最初のアイデア (そして希望) は、ios::app を使用して新しいエントリをこのファイルに追加できるというものでした。もともとこれは機能しているように見えましたが、ジャンク出力も得ていました。別のフォーラムへのヘルプの投稿では、char 配列の末尾にヌル ターミネータがないことが示唆されました。以下の例に見られるように、私はこれを適用しました (または、少なくとも表示された方法に基づいて試みました)。残念ながら、これは null ターミネータを超えて読み取れないため、 read() が適切に機能しなくなったことを意味します。

char *memoryBlockまた、C++ 標準または何かの「悪用」であり、安全ではなく、代わりに正確なサイズの配列を定義する必要があるとも言われchar memoryBlock[5]ました。任意のサイズの? その場合、どのように進めますか?以下のコードには、私が行ったさまざまな試みと、上記の提案のいくつかを含むさまざまなバリエーションを示す、コメントアウトされたさまざまなコード行が含まれています。グッドプラクティスコードを試して使用したいので、char *memoryBlock安全でない場合、または他のコード行がある場合は、これを修正したいと思います.

また、ここではテスト目的でのみ文字を書き込もうとしていることを明確にしたいと思います。そのため、バイナリ モードではなくテキスト モードで書くべきであると提案しないでください。この質問の 2 番目の部分で、以下のコードの下でさらに詳しく説明します。

最初のコード:

#include <cstdlib>
#include <iostream>
#include <fstream>
//#include <string>


int main()
{
    //char memoryBlock[5];
    char *memoryBlock;
    char *memoryBlockTwo;
    std::ifstream::pos_type size;// The number of characters to be read or written from/to the memory block.

    std::ofstream myFile;
    myFile.open("Example", std::ios::out | /*std::ios::app |*/ std::ios::binary);

    if(myFile.is_open() && myFile.good())
    {
        //myFile.seekp(0,std::ios::end);
        std::cout<<"File opening successfully completed."<<std::endl;
        memoryBlock = "THEN";
        //myFile.write(memoryBlock, (sizeof(char)*4));
        //memoryBlock = "NOW THIS";

        //strcpy_s(memoryBlock, (sizeof(char)*5),"THIS");
        //memoryBlock = "THEN";
        //strcpy(memoryBlock, "THIS");
        //memoryBlock[5] = NULL;
        myFile.write(memoryBlock, (sizeof(char)*5));
    }
    else
    {
        std::cout<<"File opening NOT successfully completed."<<std::endl;
    }
    myFile.close();

    std::ifstream myFileInput;
    myFileInput.open("Example", std::ios::in | std::ios::binary | std::ios::ate);

    if(myFileInput.is_open() && myFileInput.good())
    {
        std::cout<<"File opening successfully completed.  Again."<<std::endl;

        std::cout<<"READ:"<<std::endl;
        size = myFileInput.tellg();

        memoryBlockTwo = new char[size];
        myFileInput.seekg(0, std::ios::beg);// Get a pointer to the beginning of the file.
        myFileInput.read(memoryBlockTwo, size);

        std::cout<<memoryBlockTwo<<std::endl;

        delete[] memoryBlockTwo;
        std::cout<<std::endl<<"END."<<std::endl;
    }
    else
    {
        std::cout<<"Something has gone disasterously wrong."<<std::endl;
    }
    myFileInput.close();
    return 0;
}

私の次の試みは、ios::app を ios::binary で使用しようとしてもうまくいかず、ファイルを修正するには、すべてを読み込んで変更を加え、書き戻してから書き戻す必要があることに基づいています。ファイルの内容全体を置き換えますが、これはやや非効率的です。

ただし、以下のコードの内容を読み込んで修正することはありません。私が実際にやろうとしているのは、カスタム クラスのオブジェクトをファイルに書き込んでから、そのまま読み戻すことです。

これはうまくいくようです (ただし、ここでコードに関して何か悪いことをしている場合は指摘してください)、しかし、myFileInput.close() に到達するとアクセス違反が発生するため、型std::stringの変数を保存できないようです。std::vectorこれらのメンバー変数をコメントアウトすると、アクセス違反は発生しません。なぜこれが起こるのかについての私の最善の推測は、彼らがファイルを保存するために他のメモリへのポインタを使用していることです。データアウト。

これらのより複雑なデータ型の内容をファイルに保存することは本当に可能ですか? それとも、すべてを char、int、float などのより基本的な変数に分解する必要がありますか?

2 番目のコード:

#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

class testClass
{
public:
    testClass()
    {
        testInt = 5;
        testChar = 't';
        //testString = "Test string.";
        //testVector.push_back(3.142f);
        //testVector.push_back(0.001f);
    }
    testClass(int intInput, char charInput, std::string stringInput, float floatInput01, float floatInput02)
    {
        testInt = intInput;
        testChar = charInput;
        testArray[0] = 't';
        testArray[1] = 'e';
        testArray[2] = 's';
        testArray[3] = 't';
        testArray[4] = '\0';
        //testString = stringInput;
        //testVector = vectorInput;
        //testVector.push_back(floatInput01);
        //testVector.push_back(floatInput02);
    }
    ~testClass()
    {}

private:
    int testInt;
    char testChar;
    char testArray[5];
    //std::string testString;
    //std::vector<float> testVector;
};

int main()
{
    testClass testObject(3, 'x', "Hello there!", 9.14f, 6.662f);
    testClass testReceivedObject;
    //char memoryBlock[5];
    //char *memoryBlock;
    //char *memoryBlockTwo;
    std::ifstream::pos_type size;// The number of characters to be read or written from/to the memory block.

    std::ofstream myFile;
    myFile.open("Example", std::ios::out | /*std::ios::app |*/ std::ios::binary);

    if(myFile.is_open() && myFile.good())
    {
        //myFile.seekp(0,std::ios::end);
        std::cout<<"File opening successfully completed."<<std::endl;
        //memoryBlock = "THEN";
        //myFile.write(memoryBlock, (sizeof(char)*4));
        //memoryBlock = "NOW THIS";

        //strcpy_s(memoryBlock, (sizeof(char)*5),"THIS");
        //memoryBlock = "THEN AND NOW";
        //strcpy(memoryBlock, "THIS");
        //memoryBlock[5] = NULL;
        myFile.write(reinterpret_cast<char*>(&testObject), (sizeof(testClass)));//(sizeof(char)*5));
    }
    else
    {
        std::cout<<"File opening NOT successfully completed."<<std::endl;
    }
    myFile.close();

    std::ifstream myFileInput;
    myFileInput.open("Example", std::ios::in | std::ios::binary | std::ios::ate);

    if(myFileInput.is_open() && myFileInput.good())
    {
        std::cout<<"File opening successfully completed.  Again."<<std::endl;

        std::cout<<"READ:"<<std::endl;
        size = myFileInput.tellg();
        //memoryBlockTwo = new char[size];
        myFileInput.seekg(0, std::ios::beg);// Get a pointer to the beginning of the file.
        myFileInput.read(reinterpret_cast<char *>(&testReceivedObject), size);

        //std::cout<<memoryBlockTwo<<std::endl;

        //delete[] memoryBlockTwo;
        std::cout<<std::endl<<"END."<<std::endl;
    }
    else
    {
        std::cout<<"Something has gone disasterously wrong."<<std::endl;
    }
    myFileInput.close();
    return 0;
}

この質問が長くなってしまったことをお詫びしますが、私の問題についてできる限り多くの情報を提供することに徹底することで、これについても答えが早く現れることを願っています (修正するのが簡単な問題でさえあるかもしれませんが、ここでは時間が要因であるため、解決策を見つけるために何時間も検索しました)。私は一日中この質問を監視し、回答の助けとなる説明を提供します.

4

1 に答える 1

0

memoryBlock最初の例では、コメント アウトされており、何も初期化されていないため、何を書き込んでいるのかわかりません。std::coutコンソールにデータを表示するためにを使用しているため、それを読み込むときは、NULL終了する必要があります。そうしないと、 に割り当てられたメモリ バッファの末尾を超えて出力されmemoryBlockTwoます。

終端の null をファイルに書き込みます。

    memoryBlock = "THEN"; // 4 chars + implicit null terminator
    myFile.write(memoryBlock, (sizeof(char)*5));

または、読み取り後にバッファが終了していることを確認します。

    myFileInput.read(memoryBlockTwo, size);
    memoryBlockTwo[size - 1] = '\0';

2 番目の例では、C++ オブジェクトでそれを行わないでください。必要なコンストラクター呼び出しを回避しています。コメントアウトしたようにベクトルを使用して試してみると、期待どおりに機能しません。クラスが単純な古いデータ (非仮想関数、他のデータへのポインターがない) である場合は、おそらく問題ありませんが、それでも実際には悪い習慣です。<<C++ オブジェクトを永続化する場合は、 and>>演算子のオーバーロードを検討してください。

于 2012-04-26T15:13:26.407 に答える