Читать большой текстовый файл до определенной строки


Во-первых: извините за мой плохой английский, я немец.

У меня есть большой текстовый файл, разделенный строками (не разделенный одиночными символами), как это:

Первые данные[строка-разделитель]второй данных[строка-разделитель] ...

Я не хочу загружать весь файл в память из-за его размера (~250 МБ). Если я прочитаю весь файл с System.IO.File.ReadAllText, я получу OutOfMemoryException.

Поэтому я хочу прочитать файл до первого появления [STRING-SEPERATOR], а затем перейти к следующему строка. Это все равно, что" взять " first data из файла, обработать его и продолжить с second data, который теперь является первыми данными файла.

System.IO.StreamReader.ReadLine() мне не помогает, потому что содержимое файла-одна строка.

У вас есть идея, как читать файл до определенной строки в .NET?

Я надеюсь на некоторые идеи, спасибо.

4 2

4 ответа:

Это должно помочь вам.

private IEnumerable<string> ReadCharsByChunks(int chunkSize, string filePath)
{
    using (FileStream fs = new FileStream(filePath, FileMode.Open))
    {
        byte[] buffer = new byte[chunkSize]; 
        int currentRead;
        while ((currentRead = fs.Read(buffer, 0, chunkSize)) > 0)
        {
            yield return Encoding.Default.GetString(buffer, 0, currentRead);
        }
    }
}

private void SearchWord(string searchWord)
{
    StringBuilder builder = new StringBuilder();
    foreach (var chars in ReadCharsByChunks(2, "sample.txt"))//Can be any number
    {
        builder.Append(chars);

        var existing = builder.ToString();
        int foundIndex = -1;
        if ((foundIndex = existing.IndexOf(searchWord)) >= 0)
        {
            //Found
            MessageBox.Show("Found");

            builder.Remove(0, foundIndex + searchWord.Length);
        }
        else if (!existing.Contains(searchWord.First()))
        {
            builder.Clear();
        }
    }
}

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

StreamReader.Чтение имеет некоторые перегрузки, которые могут помочь вам. Попробуйте это:

int index, count;
index = 0;
count = 200; // or whatever number you think is better
char[] buffer = new char[count];
System.IO.StreamReader sr = new System.IO.StreamReader("Path here");
while (sr.Read(buffer, index, count) > 0) { 
    /*
    check if buffer contains your string seperator, or at least some part of it 
    if it contains a part of it, you need check the rest of the stream to make sure it's a real seporator
    do your stuff, set the index to one character after the last seporator.
    */
}

Спасибо за ответы. Вот функция, в которой я написал: VB.NET:

Public Function ReadUntil(Stream As System.IO.FileStream, UntilText As String) As String
            Dim builder As New System.Text.StringBuilder()
            Dim returnTextBuilder As New System.Text.StringBuilder()
            Dim returnText As String = String.Empty
            Dim size As Integer = CInt(UntilText.Length / 2) - 1
            Dim buffer(size) As Byte
            Dim currentRead As Integer = -1

            Do Until currentRead = 0
                Dim collected As String = Nothing
                Dim chars As String = Nothing
                Dim foundIndex As Integer = -1

                currentRead = Stream.Read(buffer, 0, buffer.Length)
                chars = System.Text.Encoding.Default.GetString(buffer, 0, currentRead)

                builder.Append(chars)
                returnTextBuilder.Append(chars)

                collected = builder.ToString()
                foundIndex = collected.IndexOf(UntilText)

                If (foundIndex >= 0) Then
                    returnText = returnTextBuilder.ToString()

                    Dim indexOfSep As Integer = returnText.IndexOf(UntilText)
                    Dim cutLength As Integer = returnText.Length - indexOfSep

                    returnText = returnText.Remove(indexOfSep, cutLength)

                    builder.Remove(0, foundIndex + UntilText.Length)

                    If (cutLength > UntilText.Length) Then
                        Stream.Position = Stream.Position - (cutLength - UntilText.Length)
                    End If

                    Return returnText
                ElseIf (Not collected.Contains(UntilText.First())) Then
                    builder.Length = 0
                End If
            Loop

            Return String.Empty
    End Function