6

Cプログラムで生成されたフラットファイルがあります。ファイル内の各レコードは、固定長のヘッダーとそれに続くデータで構成されます。ヘッダーには、次のデータのサイズを示すフィールドが含まれています。私の最終的な目標は、このフラットファイルをクエリするC#/。NETプログラムを作成することです。そのため、C#を使用してファイルを読み取る最も効率的な方法を探しています。

次のコードで7行目に相当する.NETを見つけるのに問題があります。私の知る限り、複数の読み取り(BinaryReaderを使用してヘッダーの各フィールドに1つ)を発行してから、ヘッダーに続くデータを取得するために1つの読み取りを発行する必要があります。2つの読み取り操作(1つは固定長ヘッダーを取得するための読み取り、もう1つは次のデータを取得するための読み取り)でレコードを解析する方法を学習しようとしています。

これは、C#/。NETを使用して複製しようとしているCコードです。

struct header header; /* 1-byte aligned structure (48 bytes) */
char *data;

FILE* fp = fopen("flatfile", "r");
while (!feof(fp))
{
  fread(&header, 48, 1, fp);
  /* Read header.length number of bytes to get the data. */
  data = (char*)malloc(header.length);
  fread(data, header.length, 1, fp);
  /* Do stuff... */
  free(data);
}

これはヘッダーのC構造体です。

struct header
{
    char  id[2];
    char  toname[12];
    char  fromname[12];
    char  routeto[6];
    char  routefrom[6];
    char  flag1;
    char  flag2;
    char  flag3;
    char  flag4;
    char  cycl[4];
    unsigned short len;
};

私はCヘッダーを表すためにこのC#オブジェクトを思いついた:

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi, Size = 48)]
class RouterHeader
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
    char[] Type;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
    char[] To;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)]
    char[] From;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    char[] RouteTo;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    char[] RouteFrom;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    char[] Flags;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
    char[] Cycle;

    UInt16 Length;
}
4

5 に答える 5

2

さて、あなたはStream.Read長さを読むために1つの呼び出しを使うことができます(あなたが要求したすべてを読んだことを確認するために戻り値をチェックする必要があります;あなたは一度にすべてを得ることができないかもしれません)そして次にStream.Readデータ自体をバイト配列に取得します(ここでも、何かを読み取るまでループします)。すべてがメモリに格納されたら、バッファから適切なバイトを選択して、構造体(またはクラス)のインスタンスを作成できます。

個人的には、使用するよりも明示的にこれらすべてを実行することを好みStructLayoutます。後者は常に私にはやや脆弱だと感じます。

于 2010-08-21T17:34:51.057 に答える
0

フィールドを1つずつ読み取るコード(フィールドごとに1つのステートメント)を作成することをお勧めします。これは少し余分なコードですが、より柔軟性があります。まず、メモリ内のデータ構造がファイルがディスク上にあるのと同じレイアウトである必要があるという要件から解放されます。別の構造の一部である可能性があります。たとえば、のString代わりに使用できます。char[]

また、次のことも考慮してください。構造体の最後に新しいフィールドが追加されるバージョン2.0を作成する必要がある場合はどうなりますか?あなたの例では、新しい構造体を定義する必要があり、両方の定義で立ち往生します。コードの読み取り/書き込みを選択した場合、新しい要素を条件付きで読み取ることにより、同じコードで両方をサポートできます。

于 2010-08-21T19:20:01.750 に答える
0

Hans Passant が提供したリンクに答えがあります。私は彼に信用を与えますが、彼が回答ではなくコメントとして投稿したため、どうすればよいかわかりません。

于 2010-08-25T14:26:07.340 に答える
0

別の方法として、ユニオンのような構造を使用して、一度に読み取ることができるヘッダー構造体を作成することもできます (たとえば、適切な長さの文字列として)。その構造体からの情報。

StructLayouts と FieldOffsets を使用してそのようなことを実現する方法の詳細については、こちらを参照してください

C# を使用したバイナリ ファイルの読み取りと書き込みに関する詳細な説明がここにあります。一般に、BinaryReader を使用して複数のフィールドを読み取ると、フィールド数が少ない (<40) 場合により効率的であることが示唆されています。

于 2010-08-21T15:52:29.510 に答える
0

私の傾向は、データを配列に読み取ってから、単語やロングワードなどを処理するためにシフトと追加を使用して、データ オブジェクトを適切に組み立てることです。そのようなことを処理するためのユーティリティ クラスがいくつかあります。

于 2010-08-21T22:10:25.290 に答える