debugcsharpMinor
Reading fixed-width data fields in .NET
Viewed 0 times
readingfieldswidthnetfixeddata
Problem
I'm working on a communications layer for a system that reads data from a TCPIP client that is formatted as fixed-width ASCII (yeah, old school). I was quite surprised that there seemed to be no built in way to do this, and ended up using the following simple StreamReader subclass:
```
///
/// A Stream reader that reads values as fixed width fields from a stream
///
class FixedWidthFieldStreamReader : StreamReader
{
#region Private/Protected fields
private char[] buffer; // Local buffer used to copy data before conversion
#endregion
#region Methods
///
/// Instantiates a new FixedWidthFieldStreamReader for a stream
///
/// Stream to read from
/// Initial size of the buffer used to copy data before formatting
/// Encoding to use when reading from the stream
public FixedWidthFieldStreamReader(Stream stream, int initialBufferSize, Encoding encoding)
: base(stream, encoding)
{
buffer = new char[initialBufferSize];
}
///
/// Checks if the buffer exists and is large enough,
/// and allocates or grows it if necessary.
///
/// The required buffer length
private void EnsureBufferLength(int length)
{
if (null == buffer ||
buffer.Length
/// Reads a number of bytes into the buffer
///
/// The number of bytes to read
/// True if the required number of bytes was read, false otherwise
private bool ReadToBuffer(int length)
{
EnsureBufferLength(length);
// Read from the stream
int read = Read(buffer, 0, length);
return read == length;
}
///
/// Reads a specified number of bytes from the stream and
/// converts and returns the read value.
///
/// Type of the object to read and return
/// Number of bytes in the field to read from the stream.
/// The read object if successful, or the default value for the type otherwise.
public T Read(int length) where T : IConverti
```
///
/// A Stream reader that reads values as fixed width fields from a stream
///
class FixedWidthFieldStreamReader : StreamReader
{
#region Private/Protected fields
private char[] buffer; // Local buffer used to copy data before conversion
#endregion
#region Methods
///
/// Instantiates a new FixedWidthFieldStreamReader for a stream
///
/// Stream to read from
/// Initial size of the buffer used to copy data before formatting
/// Encoding to use when reading from the stream
public FixedWidthFieldStreamReader(Stream stream, int initialBufferSize, Encoding encoding)
: base(stream, encoding)
{
buffer = new char[initialBufferSize];
}
///
/// Checks if the buffer exists and is large enough,
/// and allocates or grows it if necessary.
///
/// The required buffer length
private void EnsureBufferLength(int length)
{
if (null == buffer ||
buffer.Length
/// Reads a number of bytes into the buffer
///
/// The number of bytes to read
/// True if the required number of bytes was read, false otherwise
private bool ReadToBuffer(int length)
{
EnsureBufferLength(length);
// Read from the stream
int read = Read(buffer, 0, length);
return read == length;
}
///
/// Reads a specified number of bytes from the stream and
/// converts and returns the read value.
///
/// Type of the object to read and return
/// Number of bytes in the field to read from the stream.
/// The read object if successful, or the default value for the type otherwise.
public T Read(int length) where T : IConverti
Solution
I don't know if something does that already, but you could mimic StructLayout if you need to read multiple types of 'objects' or need reusability.
Basically just set starting point/offset and length for each property and read them.
Basically just set starting point/offset and length for each property and read them.
public class Item
{
// 3 chars starting from 0
[Layout(0, 3)]
public int Number { get; set; }
// 15 chars starting from 3
[Layout(3, 15)]
public string Text { get; set; }
// 5 chars starting from 18
[Layout(18, 5)]
public float Number2 { get; set; }
}
reader.Read()Code Snippets
public class Item
{
// 3 chars starting from 0
[Layout(0, 3)]
public int Number { get; set; }
// 15 chars starting from 3
[Layout(3, 15)]
public string Text { get; set; }
// 5 chars starting from 18
[Layout(18, 5)]
public float Number2 { get; set; }
}
reader.Read<Item>()Context
StackExchange Code Review Q#27782, answer score: 4
Revisions (0)
No revisions yet.