在C#中创建固定宽度的文件

时间:2008-09-17 18:59:20

标签: c#

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

14 个答案:

答案 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

这是一个例子: http://www.filehelpers.com/quick_start_fixed.html

答案 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)

答案 10 :(得分:0)

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

答案 11 :(得分:0)

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

如果是这样,String.PadRightString.Format会让您按计划进行。

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

之前的各种填充/格式化帖子将足够有效,但您可能对实现ISerializable感兴趣。

这是关于Object Serialization in .NET

的msdn文章