简体   繁体   English

使用一个内存流进行多次文件搜索迭代

[英]Using one memorystream for multiple file search iterations

I'm having several methods which each apply an operation to the a textfile, where the next operation requires the result of the previous operation as input: 我有几种方法,每个方法都将操作应用于文本文件,其中下一个操作需要上一个操作的结果作为输入:

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);

The code for Operation_1: Operation_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();
    }

the code for operation_2: operation_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();
    }

The code for operation_3: operation_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();
    }

Now the problem is that i'm not getting the same result as storing each intermediate result to a physical txt file on the harddisk and using that file for the next operation. 现在的问题是,与将每个中间结果存储到硬盘上的物理txt文件并将该文件用于下一个操作相比,我得到的结果不同。 A few lines and the end of the file is missing. 几行,文件末尾丢失。

Also this seems like not a very clean and generic way of doing it. 同样,这似乎不是一种非常干净和通用的方法。

So hence my question; 所以我的问题; why are my results different when using MemoryStream for the intermediate results and is there a cleaner, more flexible way of doing this? 为什么将MemoryStream用于中间结果时,我的结果有何不同?是否有一种更简洁,更灵活的方法? (I want to work towards a solution were it is possible to choose if you want to save the intermediate results or not). (如果可以选择是否保存中间结果,我想寻求一个解决方案)。

  • They are different, because you forgot to flush your writers. 它们是不同的,因为您忘记了冲洗作家。
  • The ref modifiers are not needed, because you don't create a new MemoryStream in your operations 不需要ref修饰符,因为您无需在操作中创建新的MemoryStream

Your methods would be a bit cleaner this way: 这样您的方法会更干净一些:

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();
}

The code for operation_3: operation_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();
}

I have a suggestion to change your code. 我建议更改您的代码。 Maybe instead of using Streams and TextReaders you could just work with IEnumerable. 也许不使用Streams和TextReader,而可以使用IEnumerable。

Please see the sample below (It's just a sample. Error handling not included to keep the sample simple.) 请查看下面的示例(这只是一个示例。不包括错误处理,以使示例更加简单。)

The result of the previous operation is provided as parameter to the next. 上一个操作的结果将作为下一个参数提供。 Therefore, it get's executed as following Operation3(Operation2(Operation1))). 因此,它按以下Operation3(Operation2(Operation1)))执行。

The first sample below is reading and changing the lines contained in the file line by line The second sample below is reading the whole file and changing the lines providing all lines to the next operation (lines.ToArray() reads the whole file). 下面的第一个示例逐行读取和更改文件中包含的行。下面的第二个示例读取整个文件并更改将所有行提供给下一个操作的行(lines.ToArray()读取整个文件)。

With streams you always have to be careful that they are disposed correctly and at the desired time (for example StreamReader closes the inner stream by default when StreamReader gets disposed). 使用流时,您始终必须注意在正确的时间正确放置它们(例如,在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");
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM