I often need to read/write simple arrays or structs from files and I also wanted to take advantage of the
BufferedStream
class to access files more efficiently.
And I'm always tired of instanciating 2 or 3 different objects just to open/create a file using its name.
So I wrote simple wrappers that some of you will maybe find useful.
Here is an example of how to use the classes:
BufferedFileReader reader = new BufferedFileReader(fileName);
int myInt = reader.ReadInt32();
...
float[] myArray = reader.ReadFloatArray(100);
YourStruct theStruct = reader.ReadStruct<yourstruct>();
reader.Close();
BufferedFileWriter writer = new BufferedFileWriter(fileName2);
writer.Write(myInt);
...
writer.Write(myArray);
writer.WriteStruct(theStruct);
writer.Flush();
writer.Close();
</yourstruct>
Here are the classes:
BinaryReaderEx
contains methods to read
int arrays,
float arrays, and
structs (to be used with
Marshaled structs), and also implements the
Seek
method which is not present in the current .NET Framework.
public class BinaryReaderEx : BinaryReader
{
public BinaryReaderEx(Stream input)
: base(input)
{
}
public BinaryReaderEx(Stream input, Encoding encoding)
: base(input, encoding)
{
}
public BinaryReaderEx(string fileName, FileMode fileMode)
: base(File.Open(fileName, fileMode, FileAccess.Read, FileShare.ReadWrite))
{
}
public BinaryReaderEx(string fileName)
: this(fileName, FileMode.Open)
{
}
public T ReadStruct<T>()
{
Type type = typeof(T);
int size = Marshal.SizeOf(type);
byte[] bytes = ReadBytes(size);
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
T theStruct = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), type);
handle.Free();
return theStruct;
}
public long Seek(long offset, SeekOrigin origin)
{
return BaseStream.Seek(offset, origin);
}
public int[] ReadIntArray(int length)
{
int[] array = new int[length];
byte[] bytes = ReadBytes(length * 4);
int offset = 0;
for (int i = 0; i < length; i++)
{
array[i] = BitConverter.ToInt32(bytes, offset);
offset += 4;
}
return array;
}
public float[] ReadFloatArray(int length)
{
float[] array = new float[length];
byte[] bytes = ReadBytes(length * 4);
int offset = 0;
for (int i = 0; i < length; i++)
{
array[i] = BitConverter.ToSingle(bytes, offset);
offset += 4;
}
return array;
}
}
BinaryWriterEx
contains write methods for
int and
float arrays,
structs (to be used with
Marshaled structs), and the
Seek
method as well (the current framework already contains a
Seek
method, but the offset argument is an
int
instead of a
long
...).
public class BinaryWriterEx : BinaryWriter
{
public BinaryWriterEx(Stream output)
: base(output)
{
}
public BinaryWriterEx(Stream output, Encoding encoding)
: base(output, encoding)
{
}
public BinaryWriterEx(string fileName, FileMode fileMode)
: this(File.Open(fileName, fileMode, FileAccess.Write, FileShare.ReadWrite))
{
}
public BinaryWriterEx(string fileName)
: this(fileName, FileMode.Create)
{
}
public long Seek(long offset, SeekOrigin origin)
{
Flush();
return BaseStream.Seek(offset, origin);
}
public void WriteStruct(object theStruct)
{
byte[] bytes = new byte[Marshal.SizeOf(theStruct.GetType())];
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
Marshal.StructureToPtr(theStruct, handle.AddrOfPinnedObject(), false);
handle.Free();
Write(bytes);
}
public void Write(int[] array)
{
byte[] bytes = new byte[4 * array.Length];
int offset = 0;
foreach (int value in array)
{
byte[] intBytes = BitConverter.GetBytes(value);
bytes[offset++] = intBytes[0];
bytes[offset++] = intBytes[1];
bytes[offset++] = intBytes[2];
bytes[offset++] = intBytes[3];
}
Write(bytes);
}
public void Write(float[] array)
{
byte[] bytes = new byte[4 * array.Length];
int offset = 0;
foreach (float value in array)
{
byte[] floatBytes = BitConverter.GetBytes(value);
bytes[offset++] = floatBytes[0];
bytes[offset++] = floatBytes[1];
bytes[offset++] = floatBytes[2];
bytes[offset++] = floatBytes[3];
}
Write(bytes);
}
}
BufferedFileReader
inherits from
BinaryReaderEx
and uses a
BufferedStream
to cache data.
public class BufferedFileReader : BinaryReaderEx
{
public string FileName { get; private set; }
public BufferedFileReader(string fileName, int size)
: base(new BufferedStream(new FileStream(fileName, FileMode.Open), size))
{
FileName = fileName;
}
public BufferedFileReader(string fileName)
: this(fileName, 64 * 1024)
{
}
}
BufferedFileWriter
inherits from
BinaryWriterEx
and uses a
BufferedStream
to cache data.
public class BufferedFileWriter : BinaryWriterEx
{
public string FileName { get; private set; }
public BufferedFileWriter(string fileName, int size)
: base(new BufferedStream(new FileStream(fileName, FileMode.Create), size))
{
FileName = fileName;
}
public BufferedFileWriter(string fileName)
: this(fileName, 64 * 1024)
{
}
}