2011-02-23 63 views
1

我有一个DBase IV数据库。每行都有一个带有ASCII编码字符串的备注字段,该字符串包含两个序列化的borland C++结构。我能够使用OleDb获取数据,使用ASCIIEncoding类将其重新编码为ascii,使用BinaryReader将其转换为字节,然后使用Marshal.PtrToStructure将其转换为C#结构。我得到的数据是正确的,但是当数据库被转换为c#时,数据库中的任何浮点数都是完全错误的。例如,值1149.00强制转换为764.9844,但像64.00这样的值强制转换。我可以发布一些代码和结构,但我想我首先试图保持它的简短。我知道浮点数只能精确到7位数,但我很困惑,为什么我看到这个数字是因为数值低于这个限制。Marshal C++ float to C#float precision problem

编辑:

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(); 
+0

小心发布一些代码片段? – 2011-02-23 18:28:10

+0

C++结构是双重还是编译为使用不同的浮点模型? – plinth 2011-02-23 18:35:24

+0

@Sparkie - 如果它会帮助,我会 – Carlosfocker 2011-02-23 18:39:33

回答

0

我无法直接解决问题。问题似乎来自我使用的OLE数据提供者。从数据库中收回的数据与xBaseJ提供的数据略有不同。我最终使用IKVM.NET将xBaseJ转换为CLI字节码。这使我可以用xBaseJ阅读器替换OLE数据提供者。其余的代码保持不变。

3

你在你的C#结构中有Pack = 1,但没有说你的C++结构是否打包。由于您的浮动数据(21个字符的字符串)之前有一个奇数大小的字段,可能会导致问题,并且意味着您的浮动数据正被读取错误对齐。之前的所有内容都有4个字节长,因此打包不太可能会导致您的问题。在进一步研究之前,我会确保包装符合C#和C++。

+0

C++头文件指定#pragma pack(1)。 – Carlosfocker 2011-02-24 16:16:18

+0

另请注意,此问题出现在结构中的所有浮点数上。如果价值在1000年,它会变得混乱。如果不是,那么我会得到正确的数据。 – Carlosfocker 2011-02-24 16:38:05