在C#中创建固定宽度文件的最佳方法是什么?我有一堆字段有很长的要写出来。说20,80.10,2等所有左对齐。是否有捷径可寻?
答案 0 :(得分:51)
您可以使用string.Format轻松填充带空格的值 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 |"
答案 1 :(得分:27)
这是我为可配置的固定宽度文件写入模块制作的系统。它配置了一个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。我做了那个可配置的,因为我会从规范中复制偏移量,并希望配置尽可能地与规范相似,无论作者选择的起始索引是什么。
Position标记上的Name属性引用DataTable中列的名称。
以下代码是使用LINQ-to-XML为.Net 3.5编写的,因此该方法假定它将通过具有上述配置的XElement传递,您可以在使用XDocument.Load(filename)
加载后获得该配置XML文件,然后在.Descendants("WriteFixedWidth")
对象上调用XDocument
以获取配置元素。
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,它比将不可变字符串连接在一起更快,特别是如果你正在处理多兆字节的文件。
答案 2 :(得分:9)
尝试FileHelpers:www.filehelpers.com
答案 3 :(得分:7)
使用String类的.PadRight函数(对于左对齐数据)。所以:
handle.WriteLine(s20.PadRight(20));
handle.WriteLine(s80.PadRight(80));
handle.WriteLine(s10.PadRight(10));
handle.WriteLine(s2.PadRight(2));
答案 4 :(得分:5)
答案 5 :(得分:2)
我在字符串上使用了一个扩展方法,是的,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);
}
}
答案 6 :(得分:1)
您可以使用StreamWriter并在Write(字符串)调用中使用String.Format()创建一个字符串,该字符串是给定字段的正确宽度。
答案 7 :(得分:1)
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);
}
第一个默默地忽略太长的字符串并简单地切断它的结尾,第二个通过该方法的out
参数返回截断部分。
示例:
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);
答案 8 :(得分:0)
你不能使用标准文本文件吗?您可以逐行读回数据。
答案 9 :(得分:0)
使用String.Format()
答案 10 :(得分:0)
尝试使用myString.PadRight(totalLengthForField,'')
答案 11 :(得分:0)
你的意思是你想用空格填充右边的所有数字?
如果是这样,String.PadRight或String.Format会让您按计划进行。
答案 12 :(得分:0)
您可以使用ASCIIEncoding.UTF8.GetBytes(text)将其转换为字节数组。然后将字节数组作为固定大小的记录写入文件。
UTF8表示某些字符所需的字节数不同,UTF16更可预测,每个字符2个字节。
答案 13 :(得分:0)
之前的各种填充/格式化帖子将足够有效,但您可能对实现ISerializable感兴趣。
的msdn文章