如何用C#读取VB.NET FilePut写入的二进制文件?
解决VB.NET FilePut写入的二进制文件在C#中读取的问题
问题根源
VB.NET的FilePut和FileGet依赖固定长度字符串的ANSI编码(默认对应Windows-1252,适配德语变音字符),且严格按结构体的内存布局写入字节。之前C#读取出错的核心原因:
- 用
class而非值类型struct匹配VB的结构体 - 字符集、结构体布局设置不匹配导致编码错误
- 手动读取时未严格按结构体字节长度分割,导致记录数不准
正确的C#结构体定义
必须和VB.NET的结构体完全匹配,重点设置字符集、固定长度字符串和内存布局:
' VB.NET 原结构体 Public Structure MyTestStruct <VBFixedString(20)> Public Name As String Public Age As Integer End Structure
对应C#结构体:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 4)] public struct MyTestStruct { // 对应VB的<VBFixedString(20)>,CharSet.Ansi适配德语变音 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)] public string Name; public int Age; }
实现类似VB.NET FileGet的C#方法
方法1:一次性读取所有记录(适合小文件)
using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; public static List<T> ReadAllStructs<T>(string filePath) where T : struct { int structSize = Marshal.SizeOf(typeof(T)); byte[] fileBytes = File.ReadAllBytes(filePath); if (fileBytes.Length % structSize != 0) throw new InvalidDataException("文件大小不是结构体字节数的整数倍,记录不完整"); var result = new List<T>(); GCHandle bufferHandle = GCHandle.Alloc(fileBytes, GCHandleType.Pinned); try { IntPtr basePtr = bufferHandle.AddrOfPinnedObject(); for (int i = 0; i < fileBytes.Length / structSize; i++) { IntPtr currentPtr = IntPtr.Add(basePtr, i * structSize); T structObj = Marshal.PtrToStructure<T>(currentPtr); result.Add(structObj); } } finally { bufferHandle.Free(); } return result; }
方法2:流式读取(适合大文件,避免内存过载)
using System; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; public static IEnumerable<T> ReadStructsStream<T>(string filePath) where T : struct { int structSize = Marshal.SizeOf(typeof(T)); byte[] buffer = new byte[structSize]; using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { int bytesRead; while ((bytesRead = fs.Read(buffer, 0, structSize)) > 0) { if (bytesRead != structSize) throw new InvalidDataException("文件结尾存在不完整记录"); GCHandle bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); try { T structObj = Marshal.PtrToStructure<T>(bufferHandle.AddrOfPinnedObject()); yield return structObj; } finally { bufferHandle.Free(); } } } }
关键注意事项
- 必须用
struct而非class:VB的结构体是值类型,C#用值类型才能匹配FilePut写入的二进制格式 - 字符集必须设为
CharSet.Ansi:确保德语变音字符(ä/ö/ü等)按Windows-1252编码解析,避免乱码 - 严格按结构体字节长度分割文件:通过
Marshal.SizeOf获取准确的结构体字节数,保证记录数计算正确
内容的提问来源于stack exchange,提问作者Cloudcuckoohome
相关产品推荐
相关产品推荐

