在C#中创build一个固定宽度的文件

在C#中创build一个固定宽度文件的最好方法是什么? 我有一堆有长度的字段写出来。 说20,80.10,2等所有左alignment。 是否有捷径可寻?

你可以使用string.Format来轻松地填充空格,例如

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 |" 

这是我为可configuration的固定宽度文件写入模块制作的系统。 它configuration了一个XML文件,相关部分如下所示:

 <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告诉程序你的职位是基于0还是基于1。 我做了这个configuration,因为我会复制规格偏移量,并且希望尽可能使configuration类似于规格,而不pipe作者select了哪个起始索引。

位置标签上的名称属性是指数据表中的列名称。

下面的代码是为.NET 3.5编写的,使用LINQ-to-XML,所以这个方法假定它将被传递给一个XElement,使用上面的configuration,在使用XDocument.Load(filename)加载XML文件,然后调用XDocument对象上的.Descendants("WriteFixedWidth")来获取configuration元素。

  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(); } 

引擎是StringBuilder,比将不可变串连接起来更快,特别是在处理数兆字节的文件时。

试试FileHelpers:www.filehelpers.com

以下是一个示例: http : //www.filehelpers.com/quick_start_fixed.html

使用String类的.PadRight函数(用于左alignment的数据)。 所以:

 handle.WriteLine(s20.PadRight(20)); handle.WriteLine(s80.PadRight(80)); handle.WriteLine(s10.PadRight(10)); handle.WriteLine(s2.PadRight(2)); 

我正在使用string的扩展方法,是的XML的评论可能看起来OTT这一点,但如果你想让其他开发人员重新使用…

 public static class StringExtensions { /// <summary> /// FixedWidth string extension method. Trims spaces, then pads right. /// </summary> /// <param name="self">extension method target</param> /// <param name="totalLength">The length of the string to return (including 'spaceOnRight')</param> /// <param name="spaceOnRight">The number of spaces required to the right of the content.</param> /// <returns>a new string</returns> /// <example> /// This example calls the extension method 3 times to construct a string with 3 fixed width fields of 20 characters, /// 2 of which are reserved for empty spacing on the right side. /// <code> ///const int colWidth = 20; ///const int spaceRight = 2; ///string headerLine = string.Format( /// "{0}{1}{2}", /// "Title".FixedWidth(colWidth, spaceRight), /// "Quantity".FixedWidth(colWidth, spaceRight), /// "Total".FixedWidth(colWidth, spaceRight)); /// </code> /// </example> public static string FixedWidth(this string self, int totalLength, int spaceOnRight) { if (totalLength < spaceOnRight) spaceOnRight = 1; // handle silly use. string s = self.Trim(); if (s.Length > (totalLength - spaceOnRight)) { s = s.Substring(0, totalLength - spaceOnRight); } return s.PadRight(totalLength); } } 

您可以使用StreamWriter并在Write(string)调用中使用String.Format()创build一个string,该string是给定字段的正确宽度。

你不能使用标准的文本文件吗? 您可以逐行读回数据。

尝试使用myString.PadRight(totalLengthForField,'')

你的意思是你想用空格填充右边的所有数字?

如果是这样, String.PadRight或String.Format应该让你跟踪。

您可以使用ASCIIEncoding.UTF8.GetBytes(文本)将其转换为一个字节数组。 然后将字节数组作为固定大小的logging写入文件。

UTF8在表示某些字符所需的字节数方面有所不同,UTF16更具可预测性,每个字符2个字节。

之前的各种填充/格式设置的post将会工作得足够好,但是您可能会对实现ISerializable感兴趣。

这里是一个有关.NET中的对象序列化的MSDN文章

Darren对这个问题的回答激发了我使用扩展方法,但是扩展了String ,我扩展了StringBuilder 。 我写了两个方法:

 public static StringBuilder AppendFixed(this StringBuilder sb, int length, string value) { if (String.IsNullOrWhiteSpace(value)) return sb.Append(String.Empty.PadLeft(length)); if (value.Length <= length) return sb.Append(value.PadLeft(length)); else return sb.Append(value.Substring(0, length)); } public static StringBuilder AppendFixed(this StringBuilder sb, int length, string value, out string rest) { rest = String.Empty; if (String.IsNullOrWhiteSpace(value)) return sb.AppendFixed(length, value); if (value.Length > length) rest = value.Substring(length); return sb.AppendFixed(length, value); } 

第一个人默默地忽略了太长的string,并简单地将其切断,第二个string通过方法的参数返回。

例:

 string rest; StringBuilder clientRecord = new StringBuilder(); clientRecord.AppendFixed(40, doc.ClientName, out rest); clientRecord.AppendFixed(40, rest); clientRecord.AppendFixed(40, doc.ClientAddress, out rest); clientRecord.AppendFixed(40, rest);