2008-09-17 4 views
36

C#에서 고정 너비 파일을 만드는 가장 좋은 방법은 무엇입니까? 나는 쓸 길이가 많은 들판을 가지고있다. 20,80,10,2 등 모두 왼쪽 정렬이라고 말하십시오. 이 작업을 수행하는 쉬운 방법이 있습니까?C#에서 고정 너비 파일 만들기

답변

51

당신은 및 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 |" 
+8

그러나 한 가지주의 할 점이 있습니다. 데이터가 지정된 너비보다 길면 잘리지 않습니다. 따라서 데이터를 사용해야합니다. 너비가 잠재적으로 길고 잠재적으로 길고 (반복적/비 DRY가되는) 모든 필드에서 substring (0, width)을 사용해야합니다. – brianary

+0

그냥 놓친 이래로 저를 천천히하고 있지만 그 결과가 표시되면 글꼴 사용은 너비가 고정되어 있어야합니다. – ScruffyDuck

0

표준 텍스트 파일을 사용할 수 없습니까? 데이터를 한 줄씩 다시 읽을 수 있습니다. 당신은 StreamWriter를하고 쓰기 (문자열) 호출을 사용하는 문자열에 사용할 수 있습니다

+0

하지만, 특히 형식의 텍스트 파일을 필요로하는 메인 프레임. –

0

가 ('', totalLengthForField)를 myString.PadRight를 사용해보십시오. 지정된 필드의 올바른 너비 인 문자열을 만들려면 Format()을 사용하십시오.

1

7

String 클래스의 .PadRight 함수 (왼쪽 정렬 된 데이터 용)를 사용하십시오. 따라서 :

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

ASCIIEncoding.UTF8.GetBytes (텍스트)를 사용하여 바이트 배열로 변환 할 수 있습니다. 그런 다음 바이트 배열을 고정 크기 레코드로 파일에 씁니다.

UTF8은 일부 문자를 나타내는 데 필요한 바이트 수가 다르므로 UTF16은 문자 당 2 바이트로 예측할 수 있습니다.

0

다양한 패딩/서식 게시물은 사전에 충분히 충분히 작동하지만를 ISerializable을 구현에 관심이있을 수 있습니다.

여기이 내가 구성 고정 폭 파일 작성 모듈 위해 만든 시스템이다 Object Serialization in .NET

25

에 대한 MSDN 문서입니다. 그것은 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의 열 이름을 나타냅니다.

다음 코드는 .Net 3 용으로 작성되었습니다.5, LINQ-to-XML을 사용하므로 메서드는 위의 구성을 가진 XElement를 전달할 것이라고 가정하므로 XDocument.Load(filename)을 사용하여 XML 파일을로드 한 다음 XDocument 개체에서 .Descendants("WriteFixedWidth")을 호출하여 구성을 가져올 수 있습니다 요소.

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입니다.

+3

나는 이것이 훌륭한 생각이라고 말해야합니다! +1 – Mohgeroth

+0

'Namespaces.Integration'을 참조 할 수 없습니다. 이에 대한 자세한 내용을 제공해 주시겠습니까? – vikas

+0

Vikas에 대한 자세한 내용은 https://msdn.microsoft.com/en-us/library/bb353813(v=vs.110).aspx에서 확인할 수 있습니다. XML 문서에서 네임 스페이스를 사용하는 경우 네임 스페이스가 사용됩니다. – CodingSerge

2

내가 문자열 확장 방법을 사용하고, 그래 주석 XML은

이 이 이
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); 
    } 
} 
이 이
+0

... 그리고 표준 .NET FileStream을 사용하여 물론 파일을 쓸 수 있습니다. – Darren

0

이 질문에 대런의 대답은 고무시켰다 다른 devs를 다시 사용하려면 ... 이것에 대한 OTT 보일 수 있지만, 확장 메서드를 사용하는 대신 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 매개 변수를 통해 일부를 잘라 : 나는 두 가지 방법을 썼다.

예 :

반드시 텍스트 파일을 다른 C#을 응용 프로그램에서 읽을 수 없습니다하지
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); 
관련 문제