我正在开发一个C#CE应用程序来读取由C ++程序创建的二进制文件中的数据来进行项目验证。
以下是C ++程序的编码。
// File Name: Ean2an.bin which is created by struct
struct EAN2AN_TYPE
{
__int64 ean:40; // 5 bytes, up to 12 digits
__int64 rec_no:24; // 3 bytes rec no in the c_ItemMaster File, up to 16 million records
};
// After bind data to struct, wil create the binary file
bool CreateBin_EAN2AN_TYPE()
{
if(mn_RecordCount_EAN2AN_TYPE == 0) return false;
FILE *binfile;
qsort(mc_EAN2AN_TYPE, mn_RecordCount_EAN2AN_TYPE, sizeof(struct EAN2AN_TYPE), qsort_EAN2AN_TYPE);
try
{
binfile = fopen(ms_Path_EAN2AN_TYPE, "wb");
fwrite(&mc_EAN2AN_TYPE, sizeof(struct EAN2AN_TYPE), mn_RecordCount_EAN2AN_TYPE, binfile);
}
catch(Exception ^ex)
{
TaskProgramLibrary::Message::ERR("Create EAN2AN_TYPE.bin fail!\r\n " + ex->Message);
}
finally
{
fclose(binfile);
mdw_FileSize_EAN2AN_TYPE = FileSize(ms_Path_EAN2AN_TYPE);
}
return true;
}
我尝试使用二进制读取(基于位置)读取数据并使用bitconverter转换为int64或使用Marshal.PtrToStructure,但值返回不正确。然后我试图从文件中读取5个字节而不是8个字节,但值返回stil不正确。
Below is the written C# coding
//Struct created in C#
[StructLayout(LayoutKind.Sequential)]
public struct EAN2AN_TYPE
{
[MarshalAs(UnmanagedType.I8)]
public Int64 ean;
[MarshalAs(UnmanagedType.I8)]
public Int64 rec_no;
}
//The ways i tried to read in C#
//1.Read Int64 by Binary
private void ReadByBinary()
{
using (BinaryReader b = new BinaryReader(_fs))
{
while (b.PeekChar() != 0)
{
Int64 x = b.ReadInt64();
Console.WriteLine(x.ToString());
}
}
}
//2.Using Marshal to convert the Intptr to struct's field type
private object ReadByMarshal(Type iType)
{
_oType = iType;// typeof(System.Int64);
byte[] buffer = new byte[Marshal.SizeOf(_oType)];
//byte[] buffer = new byte[5];
object oReturn = null;
try
{
_fs.Read(buffer, 0, buffer.Length);
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
oReturn = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), _oType);
handle.Free();
return oReturn;
}
catch (Exception ex)
{
throw ex;
}
}
//3. Use Binary and use bit converter to convert to Int64
private void ReadByBinaryAndUseBitConverter()
{
using (BinaryReader b = new BinaryReader(_fs))
{
byte[] x = b.ReadBytes(8);
Int64 y = BitConverter.ToInt64(x, 0);
Console.WriteLine(y);
byte[] x2 = b.ReadBytes(8);
Int64 y2 = BitConverter.ToInt64(x2,0);
Console.WriteLine(y2);
}
}
//4. Use Marshal and convert to struct
public EAN2AN_TYPE GetStructValue()
{
byte[] buffer = new byte[Marshal.SizeOf(typeof(EAN2AN_TYPE)];
EAN2AN_TYPE oReturn = new EAN2AN_TYPE();
try
{
//if (EOF) return null;
_fs.Read(buffer, 0, buffer.Length);
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
IntPtr rawDataPtr = handle.AddrOfPinnedObject();
oReturn = (EAN2AN_TYPE)Marshal.PtrToStructure(rawDataPtr, typeof(EAN2AN_TYPE));
handle.Free();
if (_fs.Position >= _fs.Length)
Close();
return oReturn;
}
catch (Exception ex)
{
throw ex;
}
}
编辑:上传二进制文件的图像
编辑:C#程序读取的前8个字节值
编辑器显示的二进制数据
有人有任何想法吗?
提前致谢
答案 0 :(得分:3)
ean
被定义为40位实体,rec_no
是24位,使整个结构只有64位。你对EAN2AN_TYPE
的定义是128位,所以显然会出现问题。我质疑编写初始代码的人的理智,但你的工作是将其恢复并使用它,这样你就可以玩你所处理的内容。
编辑:已更新以使用您指定的数据并考虑Ben的投诉
以下是获得相同结果的两种方法。一个更容易理解,因为它分步运动,另一个更快,更“正确”。我将您的示例EAN数据放入我的输入中以验证结果。
public struct EAN2AN_TYPE
{
public long ean; // can hold 5 bytes
public int rec_no; // can hold 3 bytes
}
byte[] incoming = new byte[] { 0x6F, 0x5D, 0x7C, 0xBA, 0xE3, 0x06, 0x07, 0x08 };
记忆复制:
using(var stream = new MemoryStream(incoming))
using (var reader = new BinaryReader(stream))
{
// I leave it to you to get to the data
stream.Seek(0, SeekOrigin.Begin);
// get the data, padded to where we need for endianness
var ean_bytes = new byte[8];
// read the first 5 bytes
Buffer.BlockCopy(reader.ReadBytes(5), 0, ean_bytes, 0, 5);
var rec_no_bytes = new byte[4];
// read the last 3
Buffer.BlockCopy(reader.ReadBytes(3), 0, rec_no_bytes, 0, 3);
var ean2 = new EAN2AN_TYPE();
// convert
ean2.ean = BitConverter.ToInt64(ean_bytes, 0);
ean2.rec_no = BitConverter.ToInt32(rec_no_bytes, 0);
}
位移:
using (var stream = new MemoryStream(incoming))
using (var reader = new BinaryReader(stream))
{
// I leave it to you to get to the data
stream.Seek(0, SeekOrigin.Begin);
// get the data
var data = BitConverter.ToUInt64(reader.ReadBytes(8), 0);
var ean2 = new EAN2AN_TYPE();
// shift into our data
ean2.ean = (long)(data & ~0xFFFFFF0000000000);
ean2.rec_no = (int)(data >> 40);
}
当然你可以让EAN2AN_TYPE
成为一个类,用8个字节来提供它,然后有属性访问器为你做移动的恶作剧。如果这必须是双向的(即你需要将数据放入其中一个结构中以发送回C应用程序),我会这样做。
答案 1 :(得分:1)
这可能是数据的字节顺序(如果这是一个单词)的问题。如果数据是在big-endian系统上编写的,那么你会遇到这样的问题,并且读作little-endian,反之亦然。
另一个问题是这两个字段实际上被打包成一个64位值。您可能需要读取Int64,然后使用位操作来提取这两个字段。您的所有代码似乎都是通过各种方式读取两个Int64值。
答案 2 :(得分:1)
感谢您的回复..
最初的C ++代码由供应商编写。我只能通过阅读C ++代码来尝试理解。正如我的理解..它只是创建二进制文件并写入数据.. 我无法从代码中找到任何编码/转换部分..
我试图通过代码手动将第一个ean(978086288751)转换为byte []。 字节[]是111 93 124 186 227 0 0 0,这与我得到的结果不同..
我已经测试了ctacke建议的代码。但我仍然无法得到正确的ean ..
下面是编码..(我在文件流中添加了读取二进制文件)
using (FileStream fileStream = File.OpenRead(_File))
{
MemoryStream memStream = new MemoryStream();
memStream.SetLength(fileStream.Length);
fileStream.Read(memStream.GetBuffer(), 0, (int)fileStream.Length);
using (BinaryReader reader = new BinaryReader(memStream))
{
//stream.SetLength(_fs);
// I leave it to you to get to the data
memStream.Seek(0, SeekOrigin.Begin);
// get the data, padded to where we need for endianness
byte[] ean_bytes = new byte[8];
// if this is wrong - then change param 4 to '3' to align at the other end
Buffer.BlockCopy(reader.ReadBytes(8), 0, ean_bytes, 0, 8);
//byte[] rec_no_bytes = new byte[4];
byte[] rec_no_bytes = new byte[4];
// if this is wrong - then change param 4 to '1' to align at the other end
Buffer.BlockCopy(reader.ReadBytes(3), 0, rec_no_bytes, 0, 3);
EAN2AN_TYPE ean2 = new EAN2AN_TYPE();
// convert
ean2.ean = BitConverter.ToInt64(ean_bytes, 0);
ean2.rec_no = BitConverter.ToInt32(rec_no_bytes, 0);
}
}
//结果 读5个字节:17 0 0 0 0 ean:17
//我改为
var ean_bytes = new byte[8];
Buffer.BlockCopy(reader.ReadBytes(8), 0, ean_bytes, 0, 8);
结果 读取8个字节:17 0 0 0 0 108 94 5 ean:386865365256241169
很抱歉,我仍然是新用户..无法发布任何附件.. 希望你能从我的解释中理解。