如何通过特定行分隔符来读取文本文件?

时间:2011-07-11 19:17:00

标签: c# .net file-handling

使用streamreader读取文本文件。

using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
{
     string line = sr.ReadLine();
}

我想强制该行分隔符应为\n而不是\r。那我怎么能这样做呢?

11 个答案:

答案 0 :(得分:33)

我会实现类似George的答案,但作为一种扩展方法,可以避免一次加载整个文件(未经测试,但是类似这样):

static class ExtensionsForTextReader
{
     public static IEnumerable<string> ReadLines (this TextReader reader, char delimiter)
     {
            List<char> chars = new List<char> ();
            while (reader.Peek() >= 0)
            {
                char c = (char)reader.Read ();

                if (c == delimiter) {
                    yield return new String(chars.ToArray());
                    chars.Clear ();
                    continue;
                }

                chars.Add(c);
            }
     }
}

然后可以使用:

using (StreamReader sr = new StreamReader(FileName, Encoding.Default))
{
     foreach (var line in sr.ReadLines ('\n'))
           Console.WriteLine (line);
}

答案 1 :(得分:23)

string text = sr.ReadToEnd();
string[] lines = text.Split('\r');
foreach(string s in lines)
{
   // Consume
}

答案 2 :(得分:7)

我喜欢@Pete给出的答案。我只想提一点修改。这将允许您传递字符串分隔符,而不只是一个字符:

using System;
using System.IO;
using System.Collections.Generic;
internal static class StreamReaderExtensions
{
    public static IEnumerable<string> ReadUntil(this StreamReader reader, string delimiter)
    {
        List<char> buffer = new List<char>();
        CircularBuffer<char> delim_buffer = new CircularBuffer<char>(delimiter.Length);
        while (reader.Peek() >= 0)
        {
            char c = (char)reader.Read();
            delim_buffer.Enqueue(c);
            if (delim_buffer.ToString() == delimiter || reader.EndOfStream)
            {
                if (buffer.Count > 0)
                {
                    if (!reader.EndOfStream)
                    {
                        yield return new String(buffer.ToArray()).Replace(delimiter.Substring(0, delimiter.Length - 1), string.Empty);
                    }
                    else
                    {
                        buffer.Add(c);
                        yield return new String(buffer.ToArray());
                    }
                    buffer.Clear();
                }
                continue;
            }
            buffer.Add(c);
        }
    }

    private class CircularBuffer<T> : Queue<T>
    {
        private int _capacity;

        public CircularBuffer(int capacity)
            : base(capacity)
        {
            _capacity = capacity;
        }

        new public void Enqueue(T item)
        {
            if (base.Count == _capacity)
            {
                base.Dequeue();
            }
            base.Enqueue(item);
        }

        public override string ToString()
        {
            List<String> items = new List<string>();
            foreach (var x in this)
            {
                items.Add(x.ToString());
            };
            return String.Join("", items);
        }
    }
}

答案 3 :(得分:6)

根据文件:

http://msdn.microsoft.com/en-us/library/system.io.streamreader.readline.aspx

  

一条线被定义为一个字符序列,后跟换行符   (“\ n”),回车(“\ r”)或马车回程   然后是换行符(“\ r \ n”)。

默认情况下,StreamReader ReadLine方法将通过/ n或\ r \ n

识别一行

答案 4 :(得分:4)

这是对sovemp答案的改进。抱歉,我本来想发表评论,虽然我的声誉不允许我这样做。这一改进解决了两个问题:

  1. 示例序列&#34; text \ rtest \ r \ n&#34;用分隔符&#34; \ r \ n&#34;也会 删除第一个&#34; \ r&#34;这不是意图。
  2. 当流中的最后一个字符等于分隔符时,函数会 错误地返回字符串,包括分隔符。

     let temObj:MyCustomObject  = anObject  
     temObj.customValue = "Hello"
    

答案 5 :(得分:3)

您必须自己逐个字节地解析流并处理拆分,或者您需要使用在/ r,/ n或/ r / n上拆分的默认ReadLine行为。

如果你想逐字节解析流,我会使用类似下面的扩展方法:

 public static string ReadToChar(this StreamReader sr, char splitCharacter)
    {        
        char nextChar;
        StringBuilder line = new StringBuilder();
        while (sr.Peek() > 0)
        {               
            nextChar = (char)sr.Read();
            if (nextChar == splitCharacter) return line.ToString();
            line.Append(nextChar);
        }

        return line.Length == 0 ? null : line.ToString();
    }

答案 6 :(得分:2)

我需要一个解决方案,直到&#34; \ r \ n&#34;,并且不会停留在&#34; \ n&#34;。 jp1980的解决方案有效,但在大文件上速度极慢。因此,我将Mike Sackton的解决方案转换为读取,直到找到指定的字符串。

public static string ReadToString(StreamReader sr, string splitString)
{        
    char nextChar;
    StringBuilder line = new StringBuilder();
    int matchIndex = 0;

    while (sr.Peek() > 0)
    {               
        nextChar = (char)sr.Read();
        line.Append(nextChar);
        if (nextChar == splitString[matchIndex])
        {
            if(matchIndex == splitString.Length - 1)
            {
                return line.ToString().Substring(0, line.Length - splitString.Length);
            }
            matchIndex++;
        }
        else
        {
            matchIndex = 0;
        }
    }

    return line.Length == 0 ? null : line.ToString();
}

它被称为......

using (StreamReader reader = new StreamReader(file))
{
    string line;
    while((line = ReadToString(reader, "\r\n")) != null)
    {
        Console.WriteLine(line);
    }
}

答案 7 :(得分:1)

即使您说“使用StreamReader”,因为您还说“我的情况,文件可以包含大量记录......”,我建议您尝试使用SSIS。它非常适合您尝试做的事情。您可以处理非常大的文件并轻松指定行/列分隔符。

答案 8 :(得分:0)

你可以在阅读器上使用ReadToEnd(),然后使用String.Split来分隔你认为合适的。

答案 9 :(得分:0)

此代码段将从文件读取一行,直到遇到“\ n”。

using (StreamReader sr = new StreamReader(path)) 
{
     string line = string.Empty;
     while (sr.Peek() >= 0) 
     {
          char c = (char)sr.Read();
          if (c == '\n')
          {
              //end of line encountered
              Console.WriteLine(line);
              //create new line
              line = string.Empty;
          }
          else
          {
               line += (char)sr.Read();
          }
     }
}

由于此代码逐个字符地读取,因此它将使用任意长度的文件,而不受可用内存的限制。

答案 10 :(得分:-1)

您可以使用拆分方法,在此页面上提供更多信息

http://msdn.microsoft.com/en-us/library/system.string.split.aspx

再见