3

文字列をファイルに直接保存して、後で C++ で読み取るようにしようとしています (基本的には、文字列変数を含むオブジェクト配列をファイルに保存しようとしています。これらの文字列変数は、オブジェクトのようなものを介して読み取られます)。 [0].string)。ただし、文字列変数を読み取ろうとするたびに、システムはごちゃごちゃしたエラーを返します。次のコードは、私が試みているものの基本的な部分です。

#include <iostream>
#include <fstream>
using namespace std;

/*
//this is run first to create the file and store the string
int main(){
    string reed;
    reed = "sees";
    ofstream ofs("filrsee.txt", ios::out|ios::binary);
    ofs.write(reinterpret_cast<char*>(&reed), sizeof(reed));
    ofs.close();

}*/

//this is run after that to open the file and read the string
int main(){
    string ghhh;
    ifstream ifs("filrsee.txt", ios::in|ios::binary);
    ifs.read(reinterpret_cast<char*>(&ghhh), sizeof(ghhh));
    cout<<ghhh;
    ifs.close();
    return 0;
}

2番目の部分は、私がそれを読もうとすると物事が混乱するところです. 以前に尋ねられた場合は申し訳ありませんが、同様の質問を調べてみましたが、それらのほとんどは私がやろうとしていることと少し異なるか、彼らがやろうとしていることを本当に理解していません (まだかなりこれには新しい)。

4

3 に答える 3

6

私は何を間違っていますか?

ファイルから読み取って、データを文字列構造自体に入れようとして上書きしようとしていますが、これは明らかに間違っています。

http://www.cplusplus.com/reference/iostream/istream/read/で確認できるように、使用std::stringした型が間違っていましchar *reinterpret_cast

C++ ヒント: C++ でa を使用することreinterpret_castは、(ほぼ) 常に何か間違ったことをしている兆候です。

ファイルの読み取りがなぜ複雑なのか?

昔は、ファイルを読むのは簡単でした。一部の Basic ライクな言語では、関数 を使用していましLOAD、あなたはあなたのファイルを持っていました。では、なぜ今それができないのでしょうか。

ファイルの中身がわからないからです。

  • それは文字列かもしれません。
  • これは、メモリからダンプされた生データを含むシリアル化された構造体の配列である可能性があります。
  • ライブ ストリーム、つまり継続的に追加されるファイル (ログ ファイル、stdin など) の場合もあります。
  • データを単語ごとに読み取ることができます
  • ...または行ごと...
  • または、ファイルが大きすぎて文字列に収まらないため、部分的に読み取る必要があります。
  • 等..

より一般的な解決策は、ファイル (したがって、C++ では fstream) を読み取り、関数 get ( http://www.cplusplus.com/reference/iostream/istream/get/を参照)を使用してバイト単位で読み取り、実行することです。期待する型に変換する操作を自分で行い、EOF で停止します。

std::isteamインターフェイスには、さまざまな方法でファイルを読み取るために必要なすべての機能があり ( http://www.cplusplus.com/reference/iostream/istream/を参照)、さらに、追加の非メンバー関数がありますstd::string。区切り文字が見つかるまでファイルを読み取ります (通常は "\n" ですが、何でもかまいません。 http://www.cplusplus.com/reference/string/getline/を参照してください)

しかし、私は「ロード」機能が欲しいstd::string!!!

わかったよ。

ファイルに入れるのは の内容であると仮定しますがstd::string、C スタイルの文字列との互換性を維持します。つまり、\0文字は文字列の終わりを示します (そうでない場合は、到達するまでファイルをロードする必要があります)。 EOF)。

そして、関数が戻ったら、ファイルの内容全体を完全にロードする必要があると仮定しloadFileます。

したがって、ここにloadFile関数があります:

#include <iostream>
#include <fstream>
#include <string>

bool loadFile(const std::string & p_name, std::string & p_content)
{
    // We create the file object, saying I want to read it
    std::fstream file(p_name.c_str(), std::fstream::in) ;

    // We verify if the file was successfully opened
    if(file.is_open())
    {
        // We use the standard getline function to read the file into
        // a std::string, stoping only at "\0"
        std::getline(file, p_content, '\0') ;

        // We return the success of the operation
        return ! file.bad() ;
    }

    // The file was not successfully opened, so returning false
    return false ;
}

C++11 対応のコンパイラを使用している場合は、このオーバーロードされた関数を追加できます。コストはかかりませ(C++03 では、最適化を行わないと、一時オブジェクトのコストがかかる可能性があります)。

std::string loadFile(const std::string & p_name)
{
    std::string content ;
    loadFile(p_name, content) ;
    return content ;
}

さて、完全を期すために、対応する関数を書きましたsaveFile

bool saveFile(const std::string & p_name, const std::string & p_content)
{
    std::fstream file(p_name.c_str(), std::fstream::out) ;

    if(file.is_open())
    {
        file.write(p_content.c_str(), p_content.length()) ;

        return ! file.bad() ;
    }

    return false ;
}

そして、これらの機能をテストするために使用した「メイン」は次のとおりです。

int main()
{
    const std::string name(".//myFile.txt") ;
    const std::string content("AAA BBB CCC\nDDD EEE FFF\n\n") ;

    {
        const bool success = saveFile(name, content) ;
        std::cout << "saveFile(\"" << name << "\", \"" << content << "\")\n\n"
                  << "result is: " << success << "\n" ;
    }

    {
        std::string myContent ;
        const bool success = loadFile(name, myContent) ;

        std::cout << "loadFile(\"" << name << "\", \"" << content << "\")\n\n"
                  << "result is: " << success << "\n"
                  << "content is: [" << myContent << "]\n"
                  << "content ok is: " << (myContent == content)<< "\n" ;
    }
}

もっと?

それ以上のことをしたい場合は、http: //www.cplusplus.com/reference/iostream/ で C++ IOStreams ライブラリ API を調べる必要があります。

于 2012-09-09T15:38:38.910 に答える
4

を使用してオブジェクトstd::istream::read()を読み取ることはできません。std::stringあなたができることは、ファイルのサイズを決定し、適切なサイズの文字列を作成し、データを文字列の文字配列に読み込むことです:

std::string str;
std::ifstream file("whatever");
std::string::size_type size = determine_size_of(file);
str.resize(size);
file.read(&str[0], size);

トリッキーなビットは、文字列が持つべきサイズを決定することです。たとえば、行末シーケンスが変換されるため、読み取り中に文字シーケンスが変換される可能性がある場合、これは一般的なケースで文字列を読み取ることになります。したがって、私はこのようにしないことをお勧めします。代わりに、次のようなものを使用して文字列を読み取ります。

std::string   str;
std::ifstream file("whatever");
if (std::getline(file, str, '\0')) {
     ...
}

これは、テキスト文字列に対しては問題なく動作し、ほとんどのシステムで得られる速度とほぼ同じです。たとえば、ファイルにバイナリ データが含まれているなどの理由で、ファイルにヌル文字を含めることができる場合、これはうまく機能しません。この場合、私は中間を使用しますstd::ostringstream

std::ostringstream out;
std::ifstream      file("whatever");
out << file.rdbuf();
std::string str = out.str();
于 2012-09-09T15:45:16.877 に答える
0

文字列オブジェクトは単なる char 配列ではなく、行

ifs.read(reinterpret_cast<char*>(&ghhh), sizeof(ghhh));

おそらくあなたの問題の根源です。

次の変更を適用してみてください。

char[BUFF_LEN] ghhh;
....
ifs.read(ghhh, BUFF_LEN);
于 2012-09-09T15:39:19.463 に答える