A C# equivalent of C's fread file i/o
There isn't anything wrong with using the P/Invoke marshaller, it is not unsafe and you don't have to use the unsafe keyword. Getting it wrong will just produce bad data. It can be a lot easier to use than explicitly writing the deserialization code, especially when the file contains strings. You can't use BinaryReader.ReadString(), it assumes that the string was written by BinaryWriter. Make sure however that you declare the structure of the data with a struct declaration, this.GetType() is not likely to work out well.
Here's a generic class that will make it work for any structure declaration:
class StructureReader<T> where T : struct {
private byte[] mBuffer;
public StructureReader() {
mBuffer = new byte[Marshal.SizeOf(typeof(T))];
}
public T Read(System.IO.FileStream fs) {
int bytes = fs.Read(mBuffer, 0, mBuffer.Length);
if (bytes == 0) throw new InvalidOperationException("End-of-file reached");
if (bytes != mBuffer.Length) throw new ArgumentException("File contains bad data");
T retval;
GCHandle hdl = GCHandle.Alloc(mBuffer, GCHandleType.Pinned);
try {
retval = (T)Marshal.PtrToStructure(hdl.AddrOfPinnedObject(), typeof(T));
}
finally {
hdl.Free();
}
return retval;
}
A sample declaration for the structure of the data in the file:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct Sample {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
public string someString;
}
You'll need to tweak the structure declaration and the attributes to get a match with the data in the file. Sample code that reads a file:
var data = new List<Sample>();
var reader = new StructureReader<Sample>();
using (var stream = new FileStream(@"c:\temp\test.bin", FileMode.Open, FileAccess.Read)) {
while(stream.Position < stream.Length) {
data.Add(reader.Read(stream));
}
}
What is the C# / .net equivalent of writing binary data directly to a struct?
I think you're asking about the StructLayoutAttribute and the FieldOffsetAttribute.
Example (snippet) from MSDN site:
[StructLayout(LayoutKind.Explicit, Size=16, CharSet=CharSet.Ansi)]
public class MySystemTime
{
[FieldOffset(0)]public ushort wYear;
[FieldOffset(2)]public ushort wMonth;
[FieldOffset(4)]public ushort wDayOfWeek;
[FieldOffset(6)]public ushort wDay;
[FieldOffset(8)]public ushort wHour;
[FieldOffset(10)]public ushort wMinute;
[FieldOffset(12)]public ushort wSecond;
[FieldOffset(14)]public ushort wMilliseconds;
}
How to read byte blocks into struct
Assuming this is C#, I wouldn't create a struct as a FileEntry type. I would replace char[20] with strings and use a BinaryReader - http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx to read individual fields. You must read the data in the same order as it was written.
Something like:
class FileEntry {
byte Value1;
char[] Filename;
byte Value2;
byte[] FileOffset;
float whatever;
}
using (var reader = new BinaryReader(File.OpenRead("path"))) {
var entry = new FileEntry {
Value1 = reader.ReadByte(),
Filename = reader.ReadChars(12) // would replace this with string
FileOffset = reader.ReadBytes(3),
whatever = reader.ReadFloat()
};
}
If you insist having a struct, you should make your struct immutable and create a constructor with arguments for each of your field.
Is it possible to cast a pinned byte array to a struct so that bidirectional changes are possible in C#?
You just cast the pointer (sometimes you need to go via void*
in the middle):
struct Foo
{
public int Bar;
}
static unsafe void Main()
{
byte[] buffer = new byte[10];
fixed (byte* untyped = buffer)
{
var typed = (Foo*)untyped;
typed[0].Bar = 123;
}
// buffer has the changes
}
If you need to offset into the buffer, then use byte* untyped = &buffer[offset]
.
If you want a raw struct pointer, then:
fixed (byte* ptr = buffer)
{
var typed = (Foo*)ptr;
Foo* foo = &typed[0];
foo->Bar = 123;
}
However, note that you can't pass a Foo*
to methods expecting a Foo
or ref Foo
.
Preferred way to parse a custom binary flat file?
The link Hans Passant provided has the answer. I would give him credit, but I'm not sure what to do since he posted as a comment instead of an answer.
Related Topics
Why Is Typedreference Behind the Scenes? It's So Fast and Safe... Almost Magical!
How to Get the Line Number Which Threw Exception
Generic Way to Check If Entity Exists in Entity Framework
Performing Inserts and Updates with Dapper
Can You Configure Log4Net in Code Instead of Using a Config File
Display a Image in a Console Application
How to Change Time in Datetime
C# Pattern to Prevent an Event Handler Hooked Twice
Convert Word Doc and Docx Format to PDF in .Net Core Without Microsoft.Office.Interop
Wpf Mvvm Why Use Contentcontrol + Datatemplate Views Rather Than Straight Xaml Window Views
Mongodb Gridfs with C#, How to Store Files Such as Images
How to Set the Wix Installer Version to the Current Build Version
Why Won't Control Update/Refresh Mid-Process
Displayname Attribute VS Display Attribute