C# 如何在C中的循环或递归函数中多次访问文件#

C# 如何在C中的循环或递归函数中多次访问文件#,c#,recursion,file-io,C#,Recursion,File Io,我使用以下方法打印树中的节点。此方法存在于一个应用程序类中 using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace AUV_Topology { class SpanningTree { public static Graph graph =

我使用以下方法打印树中的节点。此方法存在于一个应用程序类中

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

namespace AUV_Topology
{
    class SpanningTree
    {
        public static Graph graph = null;
        public static SpanningTree root = new SpanningTree();

        public static FileStream fs = new FileStream  ("C:/Users/Welcome/Desktop/SpanningTree.txt", FileMode.Append, FileAccess.Write);

        public static void Print(SpanningTree parent, int level)
        {
            using (StreamWriter sw = new StreamWriter(fs))
            {
                sw.WriteLine("----------------------------------------------------------------------------------------");
                sw.WriteLine("{0} Level : '{1}' ", new string(' ', 4 * level),level);
                sw.WriteLine(" , Row : '{0}', Col : '{1}'",parent.row, parent.col);
                sw.WriteLine("Length : '{0}'", parent.length);
                sw.WriteLine("----------------------------------------------------------------------------------------");

                if (parent.children != null)
                {
                    foreach (SpanningTree child in parent.children)
                    {
                        Print(child, level + 1);
                    }
                }
            }
        }
    }
}
我运行代码时出错,如下所示( 在“foreach”声明中:

无法访问已关闭的文件


作为其
Dispose
逻辑的一部分,
StreamWriter
实例将关闭底层流。因此,一种解决方案是将
FileStream
实例的创建移到
Print
方法中

在这种情况下,为了正确处置资源,可以执行以下操作:

    public static void Print(SpanningTree parent, int level)
    {
        FileStream fs = new FileStream("C:/Users/Welcome/Desktop/SpanningTree.txt", FileMode.Append, FileAccess.Write);

        using (StreamWriter sw = new StreamWriter(fs))
        {
            Print(parent, level, sw);
        }
    }

    private static void Print(SpanningTree parent, int level, StreamWriter sw)
    {
        sw.WriteLine("----------------------------------------------------------------------------------------");
        sw.WriteLine("{0} Level : '{1}' ", new string(' ', 4 * level), level);
        sw.WriteLine(" , Row : '{0}', Col : '{1}'", parent.row, parent.col);
        sw.WriteLine("Length : '{0}'", parent.length);
        sw.WriteLine("----------------------------------------------------------------------------------------");

        if (parent.children != null)
        {
            foreach (SpanningTree child in parent.children)
            {
                Print(child, level + 1, sw);
            }
        }
    }
private static IEnumerable<String> Data(SpanningTree tree, int level) {
  yield return $"-----------------------------------------------------------------";
  yield return $"{new string(' ', 4 * level)} Level : '{level}' ";
  yield return $" , Row : '{parent.row}', Col : '{parent.col}'";
  yield return $"Length : '{parent.length}'";
  yield return $"-----------------------------------------------------------------";

  if (parent.children != null) 
    foreach (SpanningTree child in parent.children)
      foreach (string line in Data(child, level + 1))
        yield return line;
}
另一种解决方案是使用
StreamWriter
类型的替代构造函数

public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen)
并将
true
传递给最后一个参数
leaveOpen
。在这种情况下,您需要确保在方法之外的某个地方处置资源


我个人建议您使用第一种方法—它稍微简单一点,而且看起来不像是性能关键型代码…

作为其
Dispose
逻辑的一部分,
StreamWriter
实例将关闭底层流。因此,一种解决方案是将
FileStream
实例的创建移到
Print
方法中

在这种情况下,为了正确处置资源,可以执行以下操作:

    public static void Print(SpanningTree parent, int level)
    {
        FileStream fs = new FileStream("C:/Users/Welcome/Desktop/SpanningTree.txt", FileMode.Append, FileAccess.Write);

        using (StreamWriter sw = new StreamWriter(fs))
        {
            Print(parent, level, sw);
        }
    }

    private static void Print(SpanningTree parent, int level, StreamWriter sw)
    {
        sw.WriteLine("----------------------------------------------------------------------------------------");
        sw.WriteLine("{0} Level : '{1}' ", new string(' ', 4 * level), level);
        sw.WriteLine(" , Row : '{0}', Col : '{1}'", parent.row, parent.col);
        sw.WriteLine("Length : '{0}'", parent.length);
        sw.WriteLine("----------------------------------------------------------------------------------------");

        if (parent.children != null)
        {
            foreach (SpanningTree child in parent.children)
            {
                Print(child, level + 1, sw);
            }
        }
    }
private static IEnumerable<String> Data(SpanningTree tree, int level) {
  yield return $"-----------------------------------------------------------------";
  yield return $"{new string(' ', 4 * level)} Level : '{level}' ";
  yield return $" , Row : '{parent.row}', Col : '{parent.col}'";
  yield return $"Length : '{parent.length}'";
  yield return $"-----------------------------------------------------------------";

  if (parent.children != null) 
    foreach (SpanningTree child in parent.children)
      foreach (string line in Data(child, level + 1))
        yield return line;
}
另一种解决方案是使用
StreamWriter
类型的替代构造函数

public StreamWriter(Stream stream, Encoding encoding, int bufferSize, bool leaveOpen)
并将
true
传递给最后一个参数
leaveOpen
。在这种情况下,您需要确保在方法之外的某个地方处置资源


我个人建议您使用第一种方法-它稍微简单一点,而且看起来不像性能关键的代码…

默认情况下,
StreamWriter
将关闭/处理底层的

有一个重载构造函数,您可以在其中传递使流保持打开状态的选项

但我会选择不同的逻辑

public static void Print(
    SpanningTree root, 
    string filename )
{
    FileStream fs = new FileStream( filename, FileMode.Append, FileAccess.Write );

    using ( StreamWriter sw = new StreamWriter( fs ) )
    {
        PrivatePrint( root, 0, sw );
    }
}

private static void PrivatePrint(
    SpanningTree parent, 
    int level, 
    StreamWriter sw )
{
    sw.WriteLine( "----------------------------------------------------------------------------------------" );
    sw.WriteLine( "{0} Level : '{1}' ", new string(' ', 4 * level), level );
    sw.WriteLine( " , Row : '{0}', Col : '{1}'", parent.row, parent.col );
    sw.WriteLine( "Length : '{0}'", parent.length );
    sw.WriteLine( "----------------------------------------------------------------------------------------" );

    if ( parent.children != null )
    {
        foreach ( SpanningTree child in parent.children )
        {
            PrivatePrint( child, level + 1, sw );
        }
    }
}

默认情况下,
StreamWriter
将关闭/处理底层

有一个重载构造函数,您可以在其中传递使流保持打开状态的选项

但我会选择不同的逻辑

public static void Print(
    SpanningTree root, 
    string filename )
{
    FileStream fs = new FileStream( filename, FileMode.Append, FileAccess.Write );

    using ( StreamWriter sw = new StreamWriter( fs ) )
    {
        PrivatePrint( root, 0, sw );
    }
}

private static void PrivatePrint(
    SpanningTree parent, 
    int level, 
    StreamWriter sw )
{
    sw.WriteLine( "----------------------------------------------------------------------------------------" );
    sw.WriteLine( "{0} Level : '{1}' ", new string(' ', 4 * level), level );
    sw.WriteLine( " , Row : '{0}', Col : '{1}'", parent.row, parent.col );
    sw.WriteLine( "Length : '{0}'", parent.length );
    sw.WriteLine( "----------------------------------------------------------------------------------------" );

    if ( parent.children != null )
    {
        foreach ( SpanningTree child in parent.children )
        {
            PrivatePrint( child, level + 1, sw );
        }
    }
}

不能以递归方式使用using语句。原因如下:

在最后一个递归调用完成后,它将处理资源(using语句超出范围)。当倒数第二个递归调用尝试处置资源时(其using语句超出范围),它会抛出异常,因为资源已被处置

考虑以下显示相同行为的控制台应用程序代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    internal class Program
    {
        public static FileStream fs = new FileStream("C:/Test/SpanningTree.txt", FileMode.Append,
            FileAccess.Write);

        public static void Print(int level)
        {

            using (StreamWriter sw = new StreamWriter(fs))
            {
                sw.WriteLine("----------------------------------------------------------------------------------------");
                sw.WriteLine("{0} Level : '{1}' ", new string(' ', 4*level), level);
                sw.WriteLine("----------------------------------------------------------------------------------------");

                if (level < 10)
                {
                    Print(level + 1);
                }

            }

        }

        private static void Main(string[] args)
        {
            Print(1);
        }

    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间控制台应用程序1
{
内部课程计划
{
publicstaticfilestreamfs=newfilestream(“C:/Test/SpanningTree.txt”,FileMode.Append,
FileAccess.Write);
公共静态无效打印(整数级)
{
使用(StreamWriter sw=新StreamWriter(fs))
{
sw.WriteLine(“----------------------------------------------------------------------------------------------------”);
sw.WriteLine(“{0}级:{1}”,新字符串(“”,4*Level),Level);
sw.WriteLine(“----------------------------------------------------------------------------------------------------”);
如果(级别<10)
{
打印(级别+1);
}
}
}
私有静态void Main(字符串[]args)
{
印刷品(1);
}
}
}
有许多方法可以解决此问题,我将在下面演示其中一种:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    internal class Program
    {
        public static FileStream fs = new FileStream("C:/Test/SpanningTree.txt", FileMode.Append,
            FileAccess.Write);

        public static void Print(StreamWriter sw, int level)
        {

            sw.WriteLine("----------------------------------------------------------------------------------------");
            sw.WriteLine("{0} Level : '{1}' ", new string(' ', 4 * level), level);
            sw.WriteLine("----------------------------------------------------------------------------------------");

            if (level < 10)
            {
                Print(level + 1);
            }
        }

        private static void Main(string[] args)
        {
            using (StreamWriter sw = new StreamWriter(fs))
            {

                Print(1);
            }
        }
    }

}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间控制台应用程序1
{
内部课程计划
{
publicstaticfilestreamfs=newfilestream(“C:/Test/SpanningTree.txt”,FileMode.Append,
FileAccess.Write);
公共静态无效打印(StreamWriter sw,整数级)
{
sw.WriteLine(“----------------------------------------------------------------------------------------------------”);
sw.WriteLine(“{0}级:{1}”,新字符串(“”,4*Level),Level);
sw.WriteLine(“----------------------------------------------------------------------------------------------------”);
如果(级别<10)
{
打印(级别+1);
}
}
私有静态void Main(字符串[]args)
{
使用(StreamWriter sw=新StreamWriter(fs))
{
印刷品(1);
}
}
}
}

不能以递归方式使用using语句。原因如下:

在最后一个递归调用完成后,它将处理资源(using语句超出范围)。当倒数第二个递归调用尝试处置资源时(其using语句超出范围),它会抛出异常,因为资源已被处置

考虑以下显示相同行为的控制台应用程序代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    internal class Program
    {
        public static FileStream fs = new FileStream("C:/Test/SpanningTree.txt", FileMode.Append,
            FileAccess.Write);

        public static void Print(int level)
        {

            using (StreamWriter sw = new StreamWriter(fs))
            {
                sw.WriteLine("----------------------------------------------------------------------------------------");
                sw.WriteLine("{0} Level : '{1}' ", new string(' ', 4*level), level);
                sw.WriteLine("----------------------------------------------------------------------------------------");

                if (level < 10)
                {
                    Print(level + 1);
                }

            }

        }

        private static void Main(string[] args)
        {
            Print(1);
        }

    }
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
命名空间控制台应用程序1
{
内部课程计划
{
publicstaticfilestreamfs=newfilestream(“C:/Test/SpanningTree.txt”,FileMode.Append,
FileAccess.Write);
公共静态无效打印(整数级)
{
使用(StreamWriter sw=新StreamWriter(fs))
{
西南书写线(“------------------------------------------------