0

各フレームでストリーム内のバイトを読み取ろうとしています。作成したファイルに保存されている位置とタイムスタンプ情報を読み取れるようにしたいと考えています。

ストリームは、記録されたスケルトン データのストリームであり、エンコードされたバイナリ形式です。

Stream recordStream;
byte[] results;
using (FileStream SourceStream = File.Open(@".....\Stream01.recorded", FileMode.Open))
{
    if (SourceStream.CanRead)
    {
        results = new byte[recordStream.Length];
        SourceStream.Read(results, 0, (int)recordStream.Length);
    }
}

ストリーム内の位置を進める前に、ファイルを読み取り、Read メソッドで現在のバイト シーケンスを読み取る必要があります。

読み取ったバイトから必要なデータ (位置とタイムスタンプ) を引き出し、それを進める前に別の変数に保存する方法はありますか?

バイナリリーダーを使用すると、これを行う機能が得られます。

BinaryReader br1 = new BinaryReader(recordStream);

ファイルを .recorded として保存しました。ファイルに何が含まれているかを確認するために.txtとしても保存しましたが、エンコードされているため、わかりません。

更新: ブレークポイントを使用してコードを実行して、binaryreader で関数に入るかどうかを確認しようとしましたが、エラーでクラッシュします: ArgumentException was unhandled. BinaryReader の初期化と宣言でストリームが読み取れませんでした

BinaryReader br1 = new BinaryReader(recordStream);

ファイルの種類は .recorded でした。

4

2 に答える 2

2

読み取ろうとしているデータの形式に関する情報が提供されていません。
ただし、 BinaryReader を使用することは、まさにあなたがする必要があることです。

ストリームからデータを読み取り、さまざまな型に変換するメソッドを公開します。
次の例を検討してください。

var filename = "pathtoyourfile";

using (var stream = File.Open(filename, FileMode.Open))
using(var reader = new BinaryReader(stream))
{
    var x = reader.ReadByte();
    var y = reader.ReadInt16();
    var z = reader.ReadBytes(10);
}

ただし、実際にはデータの形式に依存します。

更新
必要な情報はすべて提供したと思いますが、データを使用しましょう。

あなたは、データの各レコードがで始まると言います

[long: タイムスタンプ][int: フレーム番号]

using (var stream = File.Open(filename, FileMode.Open))
using(var reader = new BinaryReader(stream))
{
    var timestamp = reader.ReadInt64();
    var frameNumber = reader.ReadInt32();

    //At this point you have the timestamp and the frame number
    //you can now do whatever you want with it and decide whether or not
    //to continue, after that you just continue reading
}

読み取りを続行する方法は、レコードの残りの部分の形式によって異なります。レコード内のすべてのフィールドが特定の長さの場合、(タイムスタンプとフレーム番号の値を知っている上での選択に応じて) すべての読み取りを続行します。そのレコードのフィールドまたは次のレコードを含むストリーム内の位置に進むだけです。たとえば、各レコードの長さが 100 バイトで、最初の 2 つのフィールドを取得した後でこのレコードをスキップする場合:

stream.Seek(88, SeekOrigin.Current); 
//88 here because the first two fields take 12 bytes -> (100 - 8 + 4)

レコードが可変長の場合、解決策は似ていますが、さまざまなフィールドの長さを考慮する必要があります (可変長フィールドの前にある長さフィールドで定義する必要があります)。

最初の 8 バイトが実際にタイムスタンプを表しているかどうかを知ることに関しては、確実に知る方法はありません...最終的に、ストリームには一連の個々のバイトが含まれているだけであり、それらに与えられた意味以外にはまったく意味がありません。あなたのファイル形式によって。ファイル形式を修正する必要があるか、上記の例の「timestamp」の値が意味を成すかどうかを確認してみてください。

これは自分で定義したファイル形式ですか? もしそうなら...おそらくあなたはそれを複雑にしており、Google Protocol Buffers や Apache Thrift などのソリューションを見たいと思うかもしれません.

それでも探しているものではない場合は、質問を再定義する必要があります。

于 2012-12-11T05:47:15.613 に答える
1

あなたのコメントに基づいて:

ファイル全体の正確な定義を知る必要があります。次のファイル形式に基づいて構造体を作成します。

struct YourFileFormat {
    [FieldOffset(0)]
    public long Timestamp;

    [FieldOffset(8)]
    public int FrameNumber;

    [FieldOffset(12)]
    //.. etc..
}

次に、 を使用してBinaryReader、フレームごとに各フィールドを個別に読み取ることができます。

// assume br is an instantiated BinaryReader..
YourFileFormat file = new YourFileFormat();

file.Timestamp = br.ReadInt64();
file.FrameNumber = br.ReadInt32();
// etc..

または、ファイル全体を読み取って、マーシャリング クラスにすべてを構造体にコピーさせることもできます。

byte[] fileContent = br.ReadBytes(sizeof(YourFileFormat));

GCHandle gcHandle = GCHandle.Alloc(fileContent, GCHandleType.Pinned); // or pinning it via the "fixed" keyword in an unsafe context
file = (YourFileFormat)Marshal.PtrToStructure(gcHandle.AddrOfPinnedObject(), typeof(YourFileFormat));
gcHandle.Free();

ただし、これは、ファイルの正確なサイズがわかっていることを前提としています。ただし、この方法では..各フレーム(フレームの数がわかっていると仮定)は、この構造体内で固定サイズの配列にすることができます。

結論: スキップしたいもののサイズがわからない限り、必要なファイルからデータを取得することは期待できません。

于 2012-12-11T08:46:55.200 に答える