【问题标题】:BinaryReader or Writer.Close() is not closing properly C#BinaryReader 或 Writer.Close() 未正确关闭 C#
【发布时间】:2012-05-11 08:57:19
【问题描述】:

我有一个执行模拟并不断读取/写入二进制文件的表单应用程序。如果您让它运行,一切都会正常工作。但是,如果表单已关闭/模拟被中止,则文件流未正确关闭 - 使文件处于锁定状态。 有没有办法确保所有流都关闭?我尝试了以下 - 但它没有效果...... 非常感谢提前, T

        public BinaryWriter BinWrite;
        public BinaryReader BinRead;

        public BinaryWriter EnvBinWrite;
        public BinaryReader EnvBinRead;       

public void theForm_FormClosing(object sender, FormClosingEventArgs e)
        {

            //Close all binary file reader/writers -- crashes if it cannot overwrite files
            foreach (Building B in AllBldgs)
            {
                try
                {
                    EnvBinRead.Close();
                }
                catch
                { continue; }
                try
                {
                    EnvBinWrite.Close();
                }
                catch
                { continue; }
                try
                {
                    BinRead.Close();
                }
                catch
                { continue; }

                try
                {
                    BinWrite.Close();
                }
                catch
                { continue; }
            }
        }

【问题讨论】:

  • 有异常发生吗?
  • 不,因为你把它们都吃了。删除 try..catch 块并查看是否发生。
  • 啊,好吧...对不起,我是编码新手-我使用了 try catch,因为 Reader 和 Writer 并不总是初始化...将在没有 try catch 的情况下尝试 - 感谢您的回复
  • 在关闭它们之前检查它们是否已初始化... Try/catch 应该作为最后的手段,而不是一劳永逸的解决方案
  • 这段代码没有任何意义。你有四个流,你试图在一个完全不相关的循环内关闭每个流——(多次!)——同时你continue正在捕获,中止所有其余的关闭。 -- 从这段代码中很不清楚你想要完成什么。

标签: c# filestream binaryreader binarywriter


【解决方案1】:

您确定知道continue 关键字的用途吗?请注意,这将继续下一个 循环,而不是下一个 代码块。因此,如果关闭EnvBinRead 时发生异常,您将不会进入关闭EnvBinWrite 的块,而是继续AllBldgs 中的下一项。

要吃掉所有异常并仍然尝试关闭所有二进制写入器,您可以这样写:

foreach (Building B in AllBldgs)
{
    try
    {
        EnvBinRead.Close();
    }
    catch (Exception exp)
    { 
        Console.WriteLine("Closing EnvBinRead failed!" + exp.ToString());
    }

    try
    {
        EnvBinWrite.Close();
    }
    catch (Exception exp)
    { 
        Console.WriteLine("Closing EnvBinWrite failed!" + exp.ToString());
    }

    try
    {
        BinRead.Close();
    }
    catch (Exception exp)
    { 
        Console.WriteLine("Closing BinRead failed!" + exp.ToString());
    }

    try
    {
        BinWrite.Close();
    }
    catch (Exception exp)
    { 
        Console.WriteLine("Closing BinWrite failed!" + exp.ToString());
    }
}

请注意,简单地吃掉例外绝不是个好主意。如果您不关心读写器是否可以关闭,请在关闭之前检查它是否已按照 cmets 中的建议进行初始化。

【讨论】:

  • +1,因为这可能是问题的根源。尽管如此,我还是建议吃异常是一件坏事,如果 BinRead 可能未初始化,那么像 if (BinRead != null) BinRead.Close(); 这样的东西会更好。
  • 谢谢!如何检查是否发生异常?
  • 使用 try catch,但说 continue 意味着跳过其他所有内容并直接进入 finally。在catch块中不要说继续,让它弹出一个消息框,说有错误什么的
  • Erm - 如果发生异常,则执行 catch 块。您可以使用Debug.WriteLineTrace.WriteLine 显示消息或记录错误。我已经编辑了我的答案给你一个想法。
  • 您还应该删除循环。这里没有理由。除非您有一个真正自定义的 IEnumerable 实现,并且在您迭代它时会产生副作用,否则我无法理解您为什么要将它放在那里。 -- 在某些情况下,它永远不会尝试关闭任何文件,而在许多其他情况下,它会尝试多次关闭它们。
【解决方案2】:

你应该调用 dispose 来关闭 BinaryReader 和 Writer。

说明:

StreamReader, StreamWriter, BinaryReader and BinaryWriter 当您对它们调用 Dispose 时,它​​们都会关闭/处理它们的底层流。如果读取器/写入器只是被垃圾收集,它们不会处理流 - 您应该始终处理读取器/写入器,最好使用 using 语句。 (事实上​​,这些类都没有终结器,也不应该有。)

我个人更喜欢对流使用 using 语句。您可以非常巧妙地嵌套使用不带大括号的语句:

using (Stream stream = ...)
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever))
{
}

即使流的using 语句有些多余(除非StreamReader 构造函数抛出异常),我认为最好的做法是,如果你摆脱StreamReader 并直接使用流以后,您将拥有正确的处置语义。

【讨论】:

    【解决方案3】:

    对流使用 Using 块总是好的,使用后立即关闭它们。

    【讨论】:

    • 其实你并不知道。虽然当您真正想要在读取/写入流之后立即关闭流时,建议使用using,但可能存在需要在应用程序的整个生命周期内打开流的情况。在那种情况下,using 根本无法使用。
    猜你喜欢
    • 2018-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多