Использование одного потока памяти для нескольких итераций поиска файлов - PullRequest
0 голосов
/ 06 мая 2011

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

private TextReader input = new StreamReader("input.txt");
private TextWriter output = new StreamWriter("output.txt");
MemoryStream result_1 = new MemoryStream();
MemoryStream result_2 = new MemoryStream();

Operation_1(input, ref result_1);
Operation_2(result_1, ref result_2);
Operation_3(result_2, output);

Код для Операции_1:

   private void Operation_1(TextReader input, ref MemoryStream output)
    {
        TextWriter outputWriter = new StreamWriter(output);
        String line;

        while (input.Peek() >= 0) //while not end of file
        {
            line = input.ReadLine();
            //perform operation on line
            outputWriter.writeline(line);
        }
        input.Close();
    }

код для операции_2:

   private void Operation_2(TextReader input, ref MemoryStream output)
    {
        input.Seek(0, SeekOrigin.Begin); //reset stream to start of file
        TextReader inputReader = new StreamReader(input);
        TextWriter outputWriter = new StreamWriter(output);
        String line;

        while (inputReader.Peek() >= 0) //while not end of file
        {
            line = inputReader.ReadLine();
            //perform operation on line
            outputWriter.writeline(line);
        }
        inputReader.Close();
    }

Код для операции_3:

    private void operation_3(MemoryStream input, TextWriter output)
    {
       input.Seek(0, SeekOrigin.Begin);  //reset stream to start of file
       TextReader inputReader = new StreamReader(input);
       String line;

       while (inputReader.Peek() >= 0) //while not end of file
       {
            line = inputReader.ReadLine();
            //perform operation on line
            output.writeline(line);
       }
       inputReader.Close();
       output.Close();
    }

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

Также, похоже, это не очень чистый и общий способ сделать это.

Так отсюда и мой вопрос; почему мои результаты отличаются при использовании MemoryStream для промежуточных результатов и есть ли более чистый и гибкий способ сделать это? (Я хочу работать над решением, где можно выбрать, хотите ли вы сохранить промежуточные результаты или нет).

Ответы [ 2 ]

1 голос
/ 06 мая 2011
  • Они разные, потому что вы забыли смыть своих писателей.
  • Модификаторы ref не нужны, потому что вы не создаете новый MemoryStream в своих операциях

Ваши методы будут немного чище:

private void Operation_1(TextReader input, Stream output)
{
    TextWriter outputWriter = new StreamWriter(output);
    String line;

    outputWriter.Write(input.ReadToEnd());
    outputWriter.Flush();

    input.Close();
}

private void Operation_2(Stream input, Stream output)
{
    input.Seek(0, SeekOrigin.Begin); //reset stream to start of file
    TextReader inputReader = new StreamReader(input);
    TextWriter outputWriter = new StreamWriter(output);

    outputWriter.Write(inputReader.ReadToEnd());
    outputWriter.Flush();
    inputReader.Close();
}

Код для операции_3:

private void operation_3(Stream input, TextWriter output)
{
   input.Seek(0, SeekOrigin.Begin);  //reset stream to start of file
   TextReader inputReader = new StreamReader(input);

   output.Write(inputReader.ReadToEnd());

   inputReader.Close();
   output.Flush();
   output.Close();
}
0 голосов
/ 06 мая 2011

У меня есть предложение изменить ваш код. Возможно, вместо использования Streams и TextReaders вы могли бы просто работать с IEnumerable.

Пожалуйста, посмотрите образец ниже (Это всего лишь образец. Обработка ошибок не включена, чтобы сохранить образец простым).

Результат предыдущей операции предоставляется в качестве параметра для следующего. Следовательно, он выполняется следующим образом: Операция 3 (Операция2 (Операция1))).

Первый пример ниже читает и изменяет строки, содержащиеся в файле, построчно Второй пример ниже читает весь файл и изменяет строки, предоставляющие все строки для следующей операции (lines.ToArray () читает весь файл).

С потоками вы всегда должны быть осторожны, чтобы они располагались правильно и в нужное время (например, StreamReader закрывает внутренний поток по умолчанию, когда StreamReader удаляется).

using System;
using System.Collections.Generic;
using System.IO;
using System.Globalization;
using System.Linq;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main()
        {
            //line per line...
            File.WriteAllLines
                (
                    @"C:\temp\output.txt",
                    ChangeLines(File.ReadLines(@"C:\temp\input.txt"),
                                line =>
                                LineOperation3
                                    (
                                        LineOperation2
                                            (
                                                LineOperation1(line)
                                            )
                                    )
                        )
                );

            //lines per lines...
            File.WriteAllLines
               (
                   @"C:\temp\output2WithCount.txt",
                   ChangeLines(File.ReadLines(@"C:\temp\input.txt"),
                               lines =>
                                        LinesCountOperation
                                        (
                                            LinesCountOperation
                                            (
                                                LinesCountOperation(lines,LineOperation1),
                                                LineOperation2
                                            )
                                            , LineOperation3
                                          )
                       )
               );
        }

        private static IEnumerable<string> ChangeLines(IEnumerable<string> lines, Func<string, string> lineFunc)
        {
            foreach (var line in lines)
            {
                yield return lineFunc(line);
            }
        }

        private static IEnumerable<string> ChangeLines(IEnumerable<string> lines, Func<IEnumerable<string>, IEnumerable<string>> linesFunc)
        {
            foreach(var changedLine in linesFunc(lines))
            {
                if (changedLine != null)
                {
                    yield return changedLine;
                }
            }
        }

        private static IEnumerable<string> LinesCountOperation(IEnumerable<string> lines, Func<string, string> lineFunc)
        {
            var readAllLines = lines.ToArray();
            var linesCount = readAllLines.Count();

            foreach (var line in readAllLines)
            {
                var changedLine = lineFunc(line);
                if (changedLine == null)
                {
                    continue;
                }
                yield return string.Format(CultureInfo.InvariantCulture, "{0}-{1}", linesCount, changedLine);
            }
        }

        private static string LineOperation1(string line)
        {
            return string.Format(CultureInfo.InvariantCulture, "{0}{1}", line, "1");
        }

        private static string LineOperation2(string line)
        {
            return string.Format(CultureInfo.InvariantCulture, "{0}{1}", line, "2");
        }

        private static string LineOperation3(string line)
        {
            return string.Format(CultureInfo.InvariantCulture, "{0}{1}", line, "3");
        }
    }
}
...