新的FileStream已经关闭/处理?

时间:2010-10-13 13:52:12

标签: c# file-io compact-framework

我使用FileStreamFileMode.Open打开FileAccess.Read。不久之后,我调用一个函数来处理文件的内容。我使用Invoke进行调用,因为调用来自Thread,函数必须将结果放在Form上。该函数接受任何类型的流(我也称之为MemoryStream s而没有问题)并使用XmlTextReader来读取FileStream中的XML,但在极少数情况下甚至出于未知原因第一个Read()抛出ObjectDisposedException,如果流已经关闭,则流的CanRead属性返回false。

Thread中,FileStream是一个本地using变量,所以我认为其他线程不应该关闭它,我不会关闭它直到Invoke返回了。没有Exceptions被抛出,因此文件肯定存在(因为没有FileNotFoundException)并且应该被正确访问(因为没有UnauthorizedAccessExceptionIOException)。< / p>

我的FileStream有时候在打开之后仍然看起来像是关闭了吗?

(我可能在使用Compact Framework 3.5的Windows CE 5设备上运行我的代码并且我无法在使用XP的台式PC上重现相同的行为。)

修改 我知道,这个Invoke很丑陋,但仅凭这一点不能成为失败的理由,是吗? (并且,在大多数情况下,它根本不会失败。)

//the code in the thread
//...
using (FileStream fs = File.Open(assemblyPath + "\\white.xml", FileMode.Open, FileAccess.Read))
{
    mainForm.Instance.Invoke(new DataHandler(mainForm.Instance.handleData), new object[] { fs });
}
//...

//and the handler
public void handleData(Stream stream)
{
    infoPanel.SuspendLayout();
    try
    {
        using (XmlTextReader xml = new XmlTextReader(stream))
        {
            //it doesn't matter what is here
        }
    }
    catch{}
}

3 个答案:

答案 0 :(得分:1)

当然,这是预期的行为。您调用Invoke,它将调用封送到另一个线程。然后调用线程继续运行并且使用块退出,在流上调用Dispose。在使用UI线程中的流完成之前(也许在开始之前),就会发生此Dispose。这些操作的确切时间取决于处理器负载和其他一些因素,但它肯定不安全。

要么将流放入使用块中,要么更好,让线程执行读取并通过Invoke将结果传递给UI。

修改

正如Hans在评论中指出的那样,上面的解释应该是一个BeginInvoke调用,它在下面调用PostMessage。另一方面,Invoke使用SendMessage。两者都可能使用一些WM_COPYDATA恶作剧(我没有看到)来编组数据。

Invoke调用应该执行您发布的整个处理程序,尽管您看到的行为表示不同。从您发布的代码中,我们无法确定关闭流的内容。

我仍然会重构你在这里所做的事情,因为现在你正在通过阅读器操作捆绑UI和工作线程。我将在工作线程中执行读取工作,然后将结果传递给UI。这样可以降低读者工作导致UI不稳定的几率,并且可以消除在您阅读流时关闭流的可能性。

答案 1 :(得分:1)

我能想到的一个原因是:工作线程被中止了。这将运行使用语句生成的finally块并关闭该文件。它如何被中止是一个次要问题。线程的IsBackground属性是否设置为true?该程序是否在其他地方发生未经处理的异常并且正在关闭?当然猜对了。

答案 2 :(得分:1)

我在一些我正在研究的嵌入式主板(ARM)上看到了同样的问题。然后我创建了一个小测试。

以下代码(不涉及任何线程!)崩溃:

    using (var w = new StreamWriter(File.Create("file.txt"), System.Text.Encoding.UTF8))
    {
        for (int i = 0; i < 1000; i++)
        {
            w.WriteLine("Test");
        }
    }

此代码不会崩溃:

    using (var w = File.CreateText("file.txt"))
    {
        for (int i = 0; i < 1000; i++)
        {
            w.WriteLine("Test");
        }
    }

所以,我的猜测只能是底层本机代码处理文本文件的方式与使用File.Create()打开文件时不同。然后两个文件都以UTF-8编写,因此编码没有区别。

顺便说一句:对不起,我答案迟了一年,但我希望它会帮助某人