1

encoding/gob を使用してデータをファイルに保存し、後でロードしようとしています。新しいデータをファイルに追加し、アプリケーションを再起動した後など、保存したすべてのデータを後でロードできるようにしたいと考えています。Encode() を使用してファイルに保存している間は問題ありませんが、読み取ると、簡潔に保存されたアイテムではなく、最初に保存されたアイテムのみが常に取得されるようです。

最小限の例を次に示します: https://play.golang.org/p/patGkKDLhM

ご覧のとおり、エンコーダーに 2 回書き込み、次にそれを読み戻すことができます。ただし、ファイルを閉じて追加モードで再度開くと、書き込みは機能しているように見えますが、読み取りは最初の 2 つの要素 (以前に書き込まれたもの) に対してのみ機能します。新しく追加された 2 つの構造体を取得できません。次のエラーが表示されます。

パニック: バッファ内の余分なデータ

ディスク上のファイルで golang gob に追加することを認識しており、 https://groups.google.com/forum/#!topic/golang-nuts/bn6vjC5Abd8も読んでいます

最後に、https://gist.github.com/kjk/8015952も見つけました。これは、私がやろうとしていることがうまくいかないことを示しているようです。なんで?このエラーはどういう意味ですか?

4

1 に答える 1

3

私はencoding/gobまだパッケージを使用していません (クールに見えます。そのためのプロジェクトを見つける必要があるかもしれません)。しかし、godoc を読むと、各エンコーディングは、最初から最後までデコードされることが期待される単一のレコードであるように思えます。つまりEncode、ストリームを作成すると、結果のバイトはストリーム全体を最初から最後まで考慮した完全なセットになります。後で再度エンコードして追加することはできません。

godoc は、エンコードされたgobものは自己記述的であると述べています。エンコードされたストリームの最初に、フィールド名を含め、その後に続くデータ セットの構造体、型など全体が記述されます。次に、バイト ストリームに続くのは、エクスポートされたフィールドの値のサイズとバイト表現です。

次に、ドキュメントから省略されているのは、渡されようとしている各フィールドを含め、ストリームが最初にそれ自体を自己記述しているためであると想定できDecoderます。はDecoder、最初に記述されたものしか認識しないため、記述された後に追加された連続するバイトを認識しません。したがって、そのエラー メッセージpanic: extra data in bufferは正確です。

Playground の例では、同じエンコーダー インスタンスに 2 回エンコードしてから、ファイルを閉じています。正確に 2 つのレコードを渡し、2 つのレコードをエンコードしているため、エンコーダーの単一のインスタンスが 2 つの呼び出しを単一のエンコードされたストリームと見なす可能性があるため、これは機能する可能性があります。Encode次に、ファイル io のストリームを閉じると、gobこれで完了です。ストリームは (2 つのタイプで送信したとしても) 単一のレコードとして扱われます。

デコード関数でも同じで、同じストリームから X 回読み取っています。ただし、ファイルを閉じるときに単一のレコードを書き込んでいます。実際には、その単一のレコードに2つのタイプがあります。したがって、2 を読み取るときに機能し、正確に 2 が機能するのはなぜですか。ただし、2 を超える読み取りを行うと失敗します。

これを単一のファイルに保存する場合の解決策は、完全な「書き込み」またはエンコーダー インスタンス/セッションごとに独自のインデックスを作成する必要があることです。ディスクに書き込まれた各エントリを「開始」および「終了」マーカーでラップまたは定義できる独自の Block メソッドを形成するものもあります。そうすれば、ファイルを読み戻すときに、開始/終了マーカーにより、どのバッファーを割り当てるかが正確にわかります。バッファに単一のレコードがあれば、gob を使用Decoderしてそれをデコードします。そして、書き込みごとにファイルを閉じます。

このようなマーカーに使用するパターンは次のようなものです。

uint64:uint64
uint64:uint64
...

最初のエントリは開始バイト番号で、コロンで区切られた 2 番目のエントリはその長さです。私は通常、これを適切に呼び出された別のファイルに保存しますindexes。そうすれば、メモリにすばやく読み込むことができ、開始アドレスと終了アドレスがバイト ストリームのどこにあるかを正確に把握して、大きなファイルをストリーミングできます。

もう 1 つのオプションはgob、ファイル システムのディレクトリ構造を使用して適切に整理することで、それぞれを独自のファイルに保存することです (または、たとえば、ディレクトリを使用して型を定義することもできます)。そして、各ファイルの存在は単一のレコードです。これは、イベント ソーシング手法からレンダリングされた json を使用して、何百万ものファイルをディレクトリに整理して保存する方法です。

gob要約すると、データの最初から最後までの完全なセット、つまり単一の「レコード」のように思えます。複数のエンコーディング/複数のゴブを保存する場合は、独自のインデックスを作成して、gob保存するときに各バイトの開始とサイズ/終了を追跡する必要があります。次に、Decode各エントリを個別に作成します。

于 2016-04-03T14:43:22.853 に答える