4

ネットワーク上のファイルにデータを保存する最良の方法は何ですか。後でプログラムによって再度読み込まれます。プログラムのターゲット プラットフォームは Linux (Fedora) ですが、Windows (XP) マシンにファイルを書き出す必要があります。

これは C++ で行う必要があり、多数の書き込み/読み取りイベントが発生するため効率的である必要があり、データは簡単に読み戻せるように書き出す必要があります。

ファイル全体が読み戻されていない可能性があります。ファイル内の特定のデータ ブロックを検索して読み戻す必要があります。

単純なバイナリ ストリーム ライタでよいでしょうか。データをどのように保存する必要がありますか? - XML?

他に心配することはありますか?


更新:明確にするために、ここにピーターチェンのポイントに対するいくつかの回答があります

どうか明らかにしてください:

* ブロックを追加するだけですか、それとも削除/更新する必要がありますか?

ファイルの末尾に追加するだけで済みますが、ファイル全体を検索して、ファイル内の任意の場所から取得する必要があります

*** are all blocks of the same size?**

いいえ、データのサイズはさまざまです。フリー テキストのコメント (ここの投稿など) もあれば、特定のオブジェクトのようなデータ (パラメーターのセット) もあります。

*** is it necessary to be a single file?**

いいえ、しかし望ましい

*** by which criteria do you need to locate blocks?**

データ型別およびタイムスタンプ別。たとえば、フリー テキストなどの他のデータの中で、特定のパラメータ セットを定期的に書き出す場合、特定の日付/時刻でこれらのパラメータの値を見つけたいので、その時刻を検索する必要があります。その日付に最も近いパラメータを書き出して、読み返しました。

*** must the data be readable for other applications?**

いいえ。

*** do you need concurrent access?**

はい、読みながら書き続けているかもしれません。ただし、一度に 1 つの書き込みのみを行う必要があります。

*** Amount of data (per block / total) - kilo, mega, giga, tera?**

書き込みごとのデータ量は少なくなります...バイト数からクーペ百バイトまで-合計で数百キロバイト、数メガバイトを超えることはありません。(まだ未定です)

**> これらすべてが必要な場合、自分で作成するのは難しいでしょう。

データベースを使用することをお勧めします。それよりも少ない量が必要な場合は、お勧めできるように指定してください。**

データベースはシステムを過度に複雑にするため、残念ながらそれはオプションではありません。

4

9 に答える 9

5

あなたの質問は一般的すぎます。最初にニーズを定義し、次にファイルのレコード構造を定義し、テキスト表現を使用して保存します。Eric Stone Raymond の data metaformat、JSON そしておそらくCSVまたはXMLを見てください。peterchen の指摘はすべて関連しているようです。

于 2008-10-27T13:39:42.247 に答える
3

おそらく、固定サイズのデータ​​を含むベクターに読み込まれる別のファイルが必要です。

struct structBlockInfo
    {
        int iTimeStamp;    // TimeStamp 
        char cBlockType;   // Type of Data (PArameters or Simple Text)
        long vOffset;      // Position on the real File
    };

新しいブロックを追加するたびに、対応する情報をこのベクターに追加して保存します。

特定のブロックを読み取りたい場合は、このベクトルを検索し、対応するオフセットに対してfseek(またはその他)を使用して「実ファイル」に配置し、Xバイト(このオフセットから先頭まで)を読み取ります。その他またはファイルの最後に)そして、cBlockTypeに応じて何かにキャストします。例:

    struct structBlockText
    {   
        char cComment[];
    };

    struct structBlockValuesExample1
    {   
        int iValue1;
        int iValue2;
    };

    struct structBlockValuesExample2
    {   
        int iValue1;
        int iValue2;
        long lValue1;
        char cLittleText[];
    };

いくつかのバイトを読んでください...

fread(cBuffer, 1, iTotalBytes, p_File);

それがBLockTextだった場合...

structBlockText* p_stBlock = (structBlockText*) cBuffer;

structBlockValuesExample1の場合...

structBlockValuesExample1* p_stBlock = (structBlockValuesExample1*) cBuffer;

注:cBufferは複数のブロックを保持できることに注意してください。

于 2008-10-27T15:57:03.373 に答える
3

多数の書き込み/読み取りイベントが発生するため、効率的である必要があります。

それは効率的ではありません。

Win2K の時代には、基本的にファイルのコピーを含むプログラムを実装する必要がありました。私が見つけたのは、私のプログラムの最大のボトルネックは、各 I/O 操作のオーバーヘッドであると思われることでした。総実行時間を短縮するために私が見つけた唯一の最も効果的なことは、要求した I/O 操作の数を減らすことでした。

私はきれいなストリーム I/O を始めましたが、愚かなコンパイラがすべての文字に対して I/O を発行していたため、それはうまくいきませんでした。シェルの「コピー」コマンドと比較したそのパフォーマンスは、残念でした。次に、一度に 1 行ずつ書き出そうとしましたが、わずかに改善されました。

最終的に、ファイル全体をメモリに読み込もうとするプログラムを作成することになり、ほとんどの場合、I/O は 2 つだけになりました。1 つは読み込み、もう 1 つは書き出しです。これは私が大きな節約を見たところです。手動バッファリングを処理するために必要な余分なコードは、I/O が完了するまでの待機時間を短縮することで十分に補うことができました。

もちろん、これは7年ほど前のことなので、今はかなり変わっていると思います。確認したい場合は、自分で時間を計ってください。

于 2008-10-27T14:28:58.947 に答える
1

アプリケーションにはデータベースが必要なようです。余裕があれば使用してください。ただし、ネットワークストレージ上のファイルにはsqliteのような組み込みデータベースエンジンを使用しないでください。目的には不安定すぎる可能性があります。それでもそのようなものを使用したい場合は、独自のアクセスプロトコルを使用して独自のリーダー/ライタープロセスで使用する必要があります。代わりにXMLなどのテキストベースのファイル形式を使用する場合は安定性の懸念が適用されるため、次のことを行う必要があります。彼らも同じです。

しかし、あなたの仕事量を知らなければ、私は確信が持てません。

于 2008-10-27T13:49:41.693 に答える
1

If you are only talking about a few megabytes, I wouldn't store in on disk at all. Have a process on the network that accepts data and stores it internally, and also accepts queries on that data. If you need a record of the data, this process can also write it to the disk. Note that this sounds a lot like a database, and this indeed may be the best way to do it. I don't see how this complicates the system. In fact, it makes it much easier. Just write a class that abstracts the database, and have the rest of the code use that.

I went through this same process myself in the past, including dismissing a database as too complicated. It started off fairly simple, but after a couple of years we had written our own, poorly implemented, buggy, hard to use database. At that point, we junked our code and moved to postgres. We've never regretted the change.

于 2008-10-27T15:42:20.203 に答える
1

書き出すデータの種類を確認する必要があります。POD ではなくオブジェクトを扱うようになると、単にオブジェクトのバイナリ表現を書き出すだけでは、デシリアライズに成功するとは限りません。

テキストを「書き出すだけ」の場合、同じテキスト表現で書き出す場合、データを読み戻すのは比較的簡単です。より複雑なデータ型を書き出そうとしている場合は、おそらく boost::serialization のようなものを調べる必要があります。

于 2008-10-27T13:42:41.973 に答える
1

Boost Serializationライブラリをチェックアウトします

それらの例の1つは次のとおりです。

#include <fstream>

// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

/////////////////////////////////////////////////////////////
// gps coordinate
//
// illustrates serialization for a simple type
//
class gps_position
{
private:
    friend class boost::serialization::access;
    // When the class Archive corresponds to an output archive, the
    // & operator is defined similar to <<.  Likewise, when the class Archive
    // is a type of input archive the & operator is defined similar to >>.
    template<class Archive>
    void serialize(Archive & ar, const unsigned int version)
    {
        ar & degrees;
        ar & minutes;
        ar & seconds;
    }
    int degrees;
    int minutes;
    float seconds;
public:
    gps_position(){};
    gps_position(int d, int m, float s) :
        degrees(d), minutes(m), seconds(s)
    {}
};

int main() {
    // create and open a character archive for output
    std::ofstream ofs("filename");

    // create class instance
    const gps_position g(35, 59, 24.567f);

    // save data to archive
    {
        boost::archive::text_oarchive oa(ofs);
        // write class instance to archive
        oa << g;
        // archive and stream closed when destructors are called
    }

    // ... some time later restore the class instance to its orginal state
    gps_position newg;
    {
        // create and open an archive for input
        std::ifstream ifs("filename");
        boost::archive::text_iarchive ia(ifs);
        // read class state from archive
        ia >> newg;
        // archive and stream closed when destructors are called
    }
    return 0;
}
于 2008-10-27T19:53:16.140 に答える
1

これは、データの読み取り/書き込みのために私が持っているものです:

template<class T>
    int write_pod( std::ofstream& out, T& t )
{
    out.write( reinterpret_cast<const char*>( &t ), sizeof( T ) );
    return sizeof( T );
}

template<class T>
    void read_pod( std::ifstream& in, T& t )
{
    in.read( reinterpret_cast<char*>( &t ), sizeof( T ) );
}

これは vector や deque などでは機能しませんが、アイテムの数とそれに続くデータを書き出すだけで簡単に実行できます。

struct object {
    std::vector<small_objects> values;

    template <class archive>
    void deserialize( archive& ar ) {
        size_t size;
        read_pod( ar, size );
        values.resize( size );
        for ( int i=0; i<size; ++i ) {
            values[i].deserialize( ar );
        }
    }
}

もちろん、シリアライズおよびデシリアライズ機能を実装する必要がありますが、実装は簡単です...

于 2008-10-27T16:29:28.003 に答える
0

テキストストレージを行っていない場合は、バイナリとして保存してください。テキストは恐ろしく非効率的です。XML はさらに悪いです。ストレージ形式の効率の欠如は、より多くの時間を意味するより大きなファイル転送を前提としています. テキストを保存する必要がある場合は、zip ライブラリでフィルタリングします。

あなたの主な問題は、ファイルのロックと同時実行性です。並行して書き込み/読み取り/書き込みを行う必要がある場合、すべてが煩雑になり始めます。この時点で、ある種の DB をインストールし、ファイルを BLOB するか何かを行います。これは、この時点で独自の DB を作成することになるためです....そして誰もその車輪を再発明したくありません (もしそうなら、あなたは知っています)。自分でDB会社をやっていないか、博士課程の学生であるか、奇妙な趣味を持っている...)

于 2008-10-27T14:50:12.227 に答える