2

私はファイルからデータを読み取るプロジェクトに取り組んでおり、このデータの一部を操作する必要があります。

データはバイナリであり、ASCIIでエンコードされたテキストが含まれています。重要な場合は、データもビッグエンディアンに保存されます。

私が達成したいのは、このデータからパターンを見つけて、そのパターンの一部を操作することです。

例:(09 49 6E 76 65 6E 74 6F 72 79 0A 00 00 00 02 01 00)

これは、Inventoryにある文字数の9を表し、その後に引用符なしのASCII「Inventory」が続きます。「0A」はそのASCIIテキストの終わりを示し、続いて00 000002が在庫のサイズを示します「2」。「0100」は、インベントリ領域全体の終わりを示します。

例2:(04 53 6C 6F 74 00 02 00)

これは、スロット内の文字数の4を表し、その後に引用符なしのASCII「スロット」が続きます。「00」はASCIIテキストとスロット番号「02」の間のスペースで、その後に領域「00」の終わりが続きます。

これらのパターンと他のいくつかのパターンをファイル内で見つける必要があります。次に、パターンの一部を変更してディスクに書き込む必要があります。

ExampleModify:(04 53 6C 6F 74 00 02 00)「上から」から(04 53 6C 6F 74 00 07 00)「スロット番号「02」を「07」に変更。

もう1つの注意点は、さまざまなサイズ、長さ、および含まれるデータのファイルで検索する必要があるいくつかのパターンがありますが、全体として個別に変更する必要がある異なるデータを含むこれらのパターンの複数のセクションが存在する可能性があることです。

明確にするために:(在庫、スロット、ID、カウント)-一人の情報として扱われます。

記録される人ごとに(在庫、スロット、ID、カウント)の複数のコピーが存在する可能性があります。

この情報をユーザーに表示し、グループ内の各要素を変更するオプションをユーザーに提供したいと思います。

私は優れたプログラマーではないので、学びたいと思っています。例があれば、感謝します。アドバイスがあれば教えてください。あなたがそれをばかにすることができれば、それはさらに良いです、ありがとう。現在、作業中ですが、行き詰まっています。私が持っているものを見たい場合は私に知らせてください。

私が持っているものの要約:ファイルをbyte []に​​読み込み、配列全体をコンソールに表示します。それについてです。少しのフォーマットと、配列に読み込んだチャンクを見つけるためのデバッグ情報が含まれています。

これがpastebinの私のコードへのリンクです。リンク

(Inventory、Slot、id、Count)のすべてのオカレンスを取得できるわけではないことを認識しています。これも修正する必要があります。

編集:例(09 49 6E 76 65 6E 74 6F 72 79 0A 00 00 00 02 01 00)これは私が読んでいるファイル内のバイナリデータの固定長チャンクです。前述のように、09は文字列の長さを表します。文字列の後に続くのは(0A 00 00 00 02 01 00)です。その重要な部分は(02)です。これは、バイナリデータのスライスで変更されるのはそれだけだからです。「02」は「2」を表し、その特定の人物のレコードに(Slot、id、Count)の2つのインスタンスがあることを意味します。

(File)
    (09 Inventory 0A 00 00 00 02 01 00) // Start of person 1's record with 2 instances.
        (Slot)
        (id)
        (Count)
        (Slot)
        (id)
        (Count)
    (Rotation)  // End of person 1's record

    (09 Inventory 0A 00 00 00 04 01 00) // Start of person 2's record with 4 instances.
        (Slot)
        (id)
        (Count)
        (Slot)
        (id)
        (Count)
        (Slot)
        (id)
        (Count)
        (Slot)
        (id)
        (Count)
    (Rotation)  // End of person 2's record
(File End)

アイデアは、「id」を編集するか、インベントリに追加してスロットの数を増やし、(Slot、id、Count)のインスタンスをさらに追加したいということです。

「id」-アイテムIDが含まれます

「スロット」-インベントリスロット番号が含まれます

「カウント」-そのスロットにあるアイテムの数が含まれます。編集注:はっきりしない場合はお知らせください。ありがとうございます。

4

2 に答える 2

3

あなたはあなたが良いプログラマーではないと言いました。それでは、いくつかの基本的な提案をします。

まず、問題が発生した場合は、それを分解します。それをあなたが解決できるより単純なサブ問題に分割するようにしてください、さもなければ解決するのがより簡単になると思います。ファイル内のパターンをチェックしてから、データの一部を変更して書き戻すことをお勧めします。最初のステップとして、これらは完全な解決策に到達するために解決する必要がある主要なサブ問題であると思います。

  • ファイルを読む
  • バイナリデータのパターンを検索する
  • 変更を加える
  • 変更したデータを書き出します。

あなたは主に「パターンの検索」の部分に焦点を当てていたので、それについてさらにコメントします。他のすべての部分もトリッキーになる可能性がありますが、自分で解決するか、stackoverflowまたは他の場所で他の人がどのように解決したかについてのヒントを探すことができます。

さて、「パターンの検索」についてです。あなたの説明を読んで、

バイト配列の最初のバイトはテキストの長さのようです。C#コードでは、パターンを示すデータ配列を次のように明示的に宣言できます。

byte[] data = new byte[] { 9, 0x49, 0x6E, 0x76, 0x65, 0x6E, 0x74,
               0x6F, 0x72, 0x79, 0x0A, 0, 0, 0, 2, 1, 0 } ;

もちろん、配列を明示的に宣言することはありません。ファイル読み取り操作を介して配列を作成または入力します。この時点では、ファイルの読み取りは未解決の問題ですが、問題ありません。個別に解決できます。また、効果は同じです。ファイルの読み取りに成功すると、上記で明示的に宣言された配列のように見えるバイト配列が作成されます。

では、そのデータをどのように操作しますか?最初のバイトは文字列データの長さです。次のNバイトは文字列データです。次に、他のものがあります。

実行したい「変更」を正確に説明していませんが、提供した情報があれば、データを簡単に確認できるはずです。

配列内のデータの「スライス」を取得する場合は、これを行うことができます。

int length = (int) data[0];
byte[] s = new byte[length];
Array.Copy(data, 0, s, 0, length);
// now, s contains N bytes, representing the string

次に実行したいのは、スライスしたバイトから実際の文字列を取得することです。これを行うには、Encodingクラスを使用します。

String word = System.Text.Encoding.UTF8.GetString(s);

文字列データに続くデータのパターンがわかりません。場合によって00は、、場合によっては0Aです。

しかし、多分あなたはパターンを知っています。同じようにたどると、1つの「レコード」のすべてのデータをウォークスルーできます。レコードの最後に到達したら、最初からやり直して次のレコードを処理します。次の「レコード」に到達するための鍵は、ファイルから読み取ったデータからデータのスライスをどれだけ大きくするかを知ることです。


これにより、「ファイルの読み取り」サブ問題に戻ります。ファイルから適切な量のデータを取得する1つの方法は、最初のバイトのみを読み取り、次にファイル内でさらにNバイトを読み取ることです。(System.IO.Stream.Readを参照してください)。

byte[] size = new byte[1];
var fileStream = File.OpenRead(path);
int offset = 0;
int n;
n = fileStream.Read(size, offset, 1);
// size[0] now contains the byte of data indicating the number of bytes to follow

この時点で、次のNバイトを読み取ることができます。

int length = (int)size[0];
byte[] stringData = new byte[length];
n = fileStream.Read(stringData, offset, length);

これで、文字列を取得できます。

String word = System.Text.Encoding.UTF8.GetString(stringData);

...等々。末尾のバイトをすべて読み取ります。その時点で、暗黙的に保持されているカーソルはfileStream、ファイル内の次のレコードを指します。

于 2012-07-07T21:44:31.230 に答える
0

@Cheesoが上で言ったことに同意します。それは良いスタートです。別の解決策について説明します。

  1. 既知のすべてのセクションのオペコードを定義します(1つは0x4 0x56で始まり、もう1つは0xA 0x2で始まりますなど)。
  2. メモリ内のファイルを読み取ります。
  3. メモリ内のバイト配列にマッチングアルゴリズムを適用し、マッチングされた各パターンの開始位置を抽出します。パフォーマンス上の理由から、 Knuth-Morris-PrattBoyer-Mooreなどのよく知られた検索アルゴリズム(またはそのバリエーション)の1つを使用することをお勧めします。
  4. この時点で、見つけたすべてのパターンのすべての開始位置をアプリケーションにキャッシュする必要があります。これにはリストのディクショナリ(キーはパターンタイプ)を使用できますが、これをカスタムクラス(ファイル内のパターンIDとパターンオフセットを含む)に含めてから、リストを使用してLINQですべてにアクセスできます。 。
  5. ファイルを読んだ直後ではなく、必要に応じて実際のパターンにアクセスしてデコードします。用途はさまざまで、誰かがファイルを読み込んだ直後にすべてが表示されるわけではないと思います。

したがって、これにより、ファイル内で発生するすべてのパターンのリストがすでに表示されます。これを使用して、ある種のリストをユーザーに表示できます。

私はあなたのコードをざっと見ました。それは本当に大きく、すべてがいくつかの大きな機能に詰め込まれています。あなたはそれを少し構造化する必要があります。ファイルをロードして解析するために必要なタスクごとに1つのクラス、そして多くの小さな関数。

アプリでパターンを操作する場合、たとえば、ユーザーがパターンを変更できるようにする場合、このメカニズムを使用するとかなり簡単になります。

  • すでに持っているオフセットでデータを読み取ります。
  • あなたはオフセットを知っており、長さも知っています。変更を書き戻すときが来たら、ロードされたストリームのその特定の位置に自分を配置して上書きすることができます。

さまざまな変更のためにファイル内のデータを常に処理する必要があるので、変更したバージョンをメモリに保持したまま、データをメモリに保持し、必要なときに保存する方がよいと思います。場合によっては、メモリ内キャッシュでパターンオフセットを更新する必要があるため、最初の解析プロセスをファイルのサブセクションにのみ適用できます(プロセスを高速化するため)。

ファイルをロードした直後にパターンデータも必要な場合は、ファイルを最初にトラバースするとき(オフセットを抽出するとき)にパターンデコードプロセスを適用できます。ユーザーに表示するために、重要なものだけを別のコレクションに保持することをお勧めします(IDや表示する必要のあるテキストのみなど)。実際に必要なときにエントリ全体をロードします。

于 2012-07-07T22:03:01.653 に答える