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 this?
Select all the contents in . txt file and copy them. Select the Column A and go to “Data” tab and click “Text To Column” option. Select the Fixed Width Format option and click “Next”.
Fixed-width is a file format where data is arranged in columns, but instead of those columns being delimited by a certain character (as they are in CSV) every row is the exact same length. The application reading the file must know how long each column is.
Fixed-length format files use ordinal positions, which are offsets to identify where fields are within the record. There are no field delimiters. An end-of-record delimiter is required, even for the last record.
Fixed length files have a constant length for each field and record. There is no need to place an * in a field where there is no data since the software looks for the data in the same position in each record.
You can use string.Format to easily pad a value with spaces e.g.
string a = String.Format("|{0,5}|{1,5}|{2,5}", 1, 20, 300); string b = String.Format("|{0,-5}|{1,-5}|{2,-5}", 1, 20, 300); // 'a' will be equal to "| 1| 20| 300|" // 'b' will be equal to "|1 |20 |300 |"
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With