Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a fixed width file in C#

Tags:

c#

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?

like image 615
Brian G Avatar asked Sep 17 '08 18:09

Brian G


People also ask

How do I create a fixed width text file?

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”.

What is fixed width CSV?

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.

What is fixed length file example?

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.

What is fixed length file?

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.


2 Answers

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  |" 
like image 60
Wheelie Avatar answered Sep 23 '22 18:09

Wheelie


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.

like image 43
Chris Wenham Avatar answered Sep 23 '22 18:09

Chris Wenham