首页 > 解决方案 > Is there a memory efficient way to use 'using' within a recursive function when e.g. writing lines to a file?

问题描述

Is there a memory efficient way to use 'using' within a recursive function when e.g. writing lines to a file?

I read C# 'using' block inside a loop and it mentioned that you don't want to put a using statement inside a for loop unless you have to. (makes sense, one doesn't want multiple instances of 'using' if one doesn't need them). So in the case of a for loop if you can put it outside, you do.

But here, I have a recursive function. So the 'using' statement is going to run multiple times even if I put it outside of a for.

So what is a good or proper way of placing the 'using' statement?

I don't know if I should avoid 'using', and declare the StreamWriter object, StreamWriter writetext before the method call and dispose of it after with writetext.Dispose(). Or maybe there is a more conventional way with 'using'. Maybe wrapping the 'main' call DirSearch_basic_writetofile("c:\\aaa"); with a 'try' and putting the Dispose line in a finally. And avoiding 'using' then. That's just a thought.

// requires directory c:\texts
File.Delete(@"c:\texts\filelist.txt");
// list files and subdirectories of c:\aaa and write them to file "c:\texts\filelist.txt"
DirSearch_basic_writetofile("c:\\aaa");

// recursive function that lists files  and directories and subdirectories,in given directory  

static void DirSearch_basic_writetofile(string sDir)
{
    Console.WriteLine("DirSearch(" + sDir + ")");
    Console.WriteLine(sDir+@"\");
    try
    {
        using (StreamWriter writetext = new StreamWriter("c:\\texts\\filelist.txt",true))
        {
            writetext.WriteLine("DirSearch(" + sDir + ")");
            writetext.WriteLine(sDir);

            foreach (string f in Directory.GetFiles(sDir))
            {
                Console.WriteLine(f);
                writetext.WriteLine(f);
            }
        }

        foreach (string d in Directory.GetDirectories(sDir))
        {
            DirSearch_basic_writetofile(d);
        }

    }
    catch (System.Exception excpt)
    {
        Console.WriteLine(excpt.Message);
    }

}

标签: c#recursionmemory-managementfile-ioidisposable

解决方案


链接的事情是您在循环的所有迭代中使用相同资源的情况。在这种情况下,每次迭代都打开和关闭它没有任何意义。只要它在所有循环结束时关闭,就足够了。

相反的情况是,如果您每次迭代都使用不同的资源。比如说,在浏览文件名或完整路径列表时,依次打开每个文件名。在这种情况下,您别无选择,只能在每次迭代时拥有一个与文件相关的新实例。

递归与循环并没有真正的不同。您始终可以用递归替换循环,但并非总是如此。相同的规则适用:

  • 如果它是相同的资源,您只需将资源的创建移到递归函数之外。与其采用路径(或使用硬编码的路径),不如让它采用 Stream。这使功能很好地通用
  • 如果你有不同的资源,你别无选择,只能使用每个递归创建一个新的实例。但是我想不出任何“递归使用”的情况。

如果您必须遍历包含所有子目录的目录中的所有文件,则递归函数将在目录上递归(不需要非托管资源)。然后在递归函数内部循环来迭代当前目录中的文件(这需要非托管资源)。

编辑:

static void DirSearch_basic_writetofile(string currentDirectory, StreamWriter Output){
    //do your thing, using output as the stream you write to

    //Do recusirve calls as normal
    DirSearch_basic_writetofile(subDir, Output);
}

调用它:

using (StreamWriter OutputWriter = new StreamWriter("c:\\texts\\filelist.txt",true){
    DirSearch_basic_writetofile(startDirectory, OutputWriter);
}

推荐阅读