What is the best way to create a fixed width file in C#. I have a bunch of fields with lengths to write out. Say 20,80.10,2 etc all left aligned. Is there an easy way to do
Can't you use standard text file? You can read back data line by line.
You can use a StreamWriter and in the Write(string) call use String.Format() to create a string that is the correct width for the given field.
You mean you want to pad all numbers on the right with spaces?
If so, String.PadRight or String.Format should get you on track.
This is a system I made for a configurable Fixed Width file writing module. It's configured with an XML file, the relevant part looking like this:
<WriteFixedWidth Table="orders" StartAt="1" Output="Return">
<Position Start="1" Length="17" Name="Unique Identifier"/>
<Position Start="18" Length="3" Name="Error Flag"/>
<Position Start="21" Length="16" Name="Account Number" Justification="right"/>
<Position Start="37" Length="8" Name="Member Number"/>
<Position Start="45" Length="4" Name="Product"/>
<Position Start="49" Length="3" Name="Paytype"/>
<Position Start="52" Length="9" Name="Transit Routing Number"/>
</WriteFixedWidth>
StartAt tells the program whether your positions are 0-based or 1-based. I made that configurable because I would be copying down offsets from specs and wanted to have the config resemble the spec as much as possible, regardless of what starting index the author chose.
The Name attribute on the Position tags refer to the names of columns in a DataTable.
The following code was written for .Net 3.5, using LINQ-to-XML, so the method assumed it'd be passed an XElement with the above configuration, which you can get after you use XDocument.Load(filename)
to load the XML file, then call .Descendants("WriteFixedWidth")
on the XDocument
object to get the configuration element.
public void WriteFixedWidth(System.Xml.Linq.XElement CommandNode, DataTable Table, Stream outputStream)
{
StreamWriter Output = new StreamWriter(outputStream);
int StartAt = CommandNode.Attribute("StartAt") != null ? int.Parse(CommandNode.Attribute("StartAt").Value) : 0;
var positions = from c in CommandNode.Descendants(Namespaces.Integration + "Position")
orderby int.Parse(c.Attribute("Start").Value) ascending
select new
{
Name = c.Attribute("Name").Value,
Start = int.Parse(c.Attribute("Start").Value) - StartAt,
Length = int.Parse(c.Attribute("Length").Value),
Justification = c.Attribute("Justification") != null ? c.Attribute("Justification").Value.ToLower() : "left"
};
int lineLength = positions.Last().Start + positions.Last().Length;
foreach (DataRow row in Table.Rows)
{
StringBuilder line = new StringBuilder(lineLength);
foreach (var p in positions)
line.Insert(p.Start,
p.Justification == "left" ? (row.Field<string>(p.Name) ?? "").PadRight(p.Length,' ')
: (row.Field<string>(p.Name) ?? "").PadLeft(p.Length,' ')
);
Output.WriteLine(line.ToString());
}
Output.Flush();
}
The engine is StringBuilder, which is faster than concatenating immutable strings together, especially if you're processing multi-megabyte files.
Try using myString.PadRight(totalLengthForField, ' ')
You could use ASCIIEncoding.UTF8.GetBytes(text) to convert it to a byte array. Then write the byte arrays out to the file as a fixed-size record.
UTF8 varies in the number of bytes required to represent some characters, UTF16 is a little more predictable, 2 bytes per character.