1

DBase IV データベースがあります。各行には、シリアル化された 2 つの borland c++ 構造を保持する ASCII エンコード文字列を含むメモ フィールドがあります。OleDb を使用してデータを取得し、ASCIIEncoding クラスを使用して ascii に再エンコードし、BinaryReader を使用してバイトに変換し、Marshal.PtrToStructure を使用して C# 構造体にキャストすることができます。私が取得したデータは正しいですが、データベースで大きすぎるフロートは、c# にキャストすると完全に間違っています。たとえば、1149.00 の値は 764.9844 にキャストされますが、64.00 のような値は正常にキャストされます。コードと構造の一部を投稿できますが、最初は短くしようとしていたと思います。float は 7 桁までしか正確ではないことは知っていますが、値がその制限を下回っているため、なぜこれが表示されるのか混乱しています。

編集:

struct cplusplusstruct // from the c++ code
{
  int   Number;
  float P;
  float ZP;
  float Hours;
  int   Month;
  int   Day;
  int   Year;
  int   Hour;
  int   Minute;
  int   Second;
  ULONG UPCTime;
  int   B;
  char  Name[21];
  float L;
  float H;
  float S;
}


[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct csharpstruct  //The C# struct I created
{
     public int Number;
     public float Pr;
     public float ZP;
     public float Hours;
     public int Month;
     public int Day;
     public int Year;
     public int Hour;
     public int Minute;
     public int Second;
     public UInt32 UPCTime;
     public int B;
 [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 21)]
     public string Name;
     public float L;
     public float H;
     public float S;
 }


//OLE DB Connection and query ...

//Casting data to struct
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] blob = encoding.GetBytes(memoString);
MemoryStream memoryStream = new MemoryStream(blob);
BinaryReader binaryReader = new BinaryReader(memoryStream);

int dataSize = Marshal.SizeOf(typeof(csharpstruct));
GCHandle handle = GCHandle.Alloc(binaryReader.ReadBytes(dataSize), GCHandleType.Pinned);
csharpstruct data = (csharpstruct) Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(csharpstruct));

編集: 以下は、キャストを使用せずにデータを正常に読み取る Java コードです。

org.xBaseJ.DBF dbf = new org.xBaseJ.DBF(dbPath);
org.xBaseJ.DBF dbf = new org.xBaseJ.DBF(dbPath);
MemoField m = (MemoField) dbf.getField("MEMOFIELD");

Charset charset = Charset.forName("US-ASCII");
CharsetDecoder decoder = charset.newDecoder();
ByteBuffer trendBytes = ByteBuffer.wrap(m.getBytes());
trendBytes.order(ByteOrder.LITTLE_ENDIAN);
trendBytes.getInt();
trendBytes.getFloat();
4

2 に答える 2

3

C#構造体がありますPack = 1が、C++構造体がパックされているかどうかはわかりません。フロートの直前に奇数サイズのフィールド(21文字の文字列)があるため、問題が発生し、フロートの読み取りがずれている可能性があります。4バイトの長さになる前はすべてなので、パッキングによって問題が発生する可能性は低くなります。先に進む前に、C#とC++の両方でパッキングが一致していることを確認します。

于 2011-02-23T21:45:31.017 に答える
0

問題を直接解決することはできませんでした。問題は、使用していた OLE データ プロバイダーにあるようです。データベースから取得したデータは、xBaseJが提供したものとはわずかに異なっていました。IKVM.NETを使用して xBaseJ を CLI バイトコードに変換することになりました。これにより、OLE データ プロバイダーを xBaseJ リーダーに置き換えることができました。私のコードの残りの部分は変更されていません。

于 2011-03-08T16:34:17.490 に答える