Как прочитать текстовый файл по определенному символу разделителя строк? - PullRequest
32 голосов
/ 11 июля 2011

Чтение текстового файла с помощью Streamreader.

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

Я хочу, чтобы разделитель строк был \n, а не \r. Так как я могу это сделать?

Ответы [ 11 ]

33 голосов
/ 11 июля 2011

Я бы реализовал что-то вроде ответа Джорджа, но как метод расширения, который позволяет избежать загрузки всего файла сразу (не проверено, но что-то вроде этого):

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);
}
22 голосов
/ 11 июля 2011
string text = sr.ReadToEnd();
string[] lines = text.Split('\r');
foreach(string s in lines)
{
   // Consume
}
7 голосов
/ 10 июля 2015

Мне понравился ответ, который дал @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);
        }
    }
}
6 голосов
/ 11 июля 2011

Согласно документации:

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

Строка определяется как последовательность символов, за которой следует перевод строки ("\ n"), возврат каретки("\ r") или возврат каретки, за которым сразу следует перевод строки ("\ r \ n").

По умолчанию метод StreamReader ReadLine распознает строку обоими / либо \n или \ r

4 голосов
/ 24 февраля 2017

Это улучшение совэмпа.Извините, я бы хотел прокомментировать, хотя моя репутация не позволяет мне это делать.Это улучшение решает 2 проблемы:

  1. пример последовательности «text \ rtest \ r \ n» с разделителем «\ r \ n» также удалит первый «\ r», который не предназначен.
  2. когда последние символы в потоке равны разделителю, функция ошибочно возвращает строку, включая разделители.

    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)
                        {
                            buffer.Add(c);
                            yield return new String(buffer.ToArray()).Substring(0, buffer.Count - delimeter.Length);
                        }
                        else
                        {
                            buffer.Add(c);
                            if (delim_buffer.ToString() != delimiter)
                                yield return new String(buffer.ToArray());
                            else
                                yield return new String(buffer.ToArray()).Substring(0, buffer.Count - delimeter.Length);
                        }
                        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 голосов
/ 11 июля 2011

Вы должны либо самостоятельно анализировать побитовый поток и обрабатывать разбиение, либо вам нужно использовать поведение ReadLine по умолчанию, которое разделяется на / r, / n или /r/n.

Если вы хотите анализировать поток побайтово, я бы использовал что-то вроде следующего метода расширения:

 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();
    }
2 голосов
/ 21 июля 2017

Мне нужно решение, которое читает до "\ r \ n" и не останавливается на "\ n". Решение jp1980 работало, но было очень медленным для большого файла. Итак, я преобразовал решение Майка Сактона в чтение, пока не будет найдена указанная строка.

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);
    }
}
1 голос
/ 11 июля 2011

Несмотря на то, что вы сказали «Использование StreamReader», так как вы также сказали «В моем случае, файл может содержать тонны записей ...», я бы порекомендовал попробовать SSIS. Это идеально подходит для того, что вы пытаетесь сделать. Вы можете обработать очень большой файл и легко указать разделители строк / столбцов.

0 голосов
/ 11 июля 2011

Этот фрагмент кода будет читать строку из файла, пока не встретит "\ 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();
          }
     }
}

Поскольку этот код читает символ за символом, он будет работать с файлом любой длины без ограничения доступной памятью.

0 голосов
/ 11 июля 2011

Вы можете использовать метод разделения, больше информации на этой странице

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

Пока

...