using 子句会关闭此流吗?

Posted

技术标签:

【中文标题】using 子句会关闭此流吗?【英文标题】:Will a using clause close this stream? 【发布时间】:2010-10-16 23:30:21 【问题描述】:

我显然已经养成了一个不好的编码习惯。这是我一直在编写的代码示例:

using(StreamReader sr = new StreamReader(File.Open("somefile.txt", FileMode.Open)))

    //read file

File.Move("somefile.txt", "somefile.bak"); //can't move, get exception that I the file is open

我认为因为using 子句在StreamReader 上显式调用Close()Dispose(),所以FileStream 也将被关闭。

我可以解决我遇到的问题的唯一方法是将上面的块更改为:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open))

  using(StreamReader sr = new StreamReader(fs))
  
    //read file
  


File.Move("somefile.txt", "somefile.bak"); // can move file with no errors

是否应该通过在第一个块中处理来关闭StreamReader 也关闭底层FileStream?还是我弄错了?

编辑

我决定发布真正的违规代码块,看看我们是否能找到这个问题的根源。我现在只是好奇。

我以为我的using 子句有问题,所以我将所有内容都展开,但每次都无法复制。我在这个方法调用中创建了文件,所以我认为没有其他任何东西在文件上打开了句柄。我还验证了 Path.Combine 调用返回的字符串是正确的。

private static void GenerateFiles(List<Credit> credits)

    Account i;
    string creditFile = Path.Combine(Settings.CreditLocalPath, DateTime.Now.ToString("MMddyy-hhmmss") + ".credits");

    StreamWriter creditsFile = new StreamWriter(File.Open(creditFile, FileMode.Create));

    creditsFile.WriteLine("code\inc");

    foreach (Credit c in credits)
    
        if (DataAccessLayer.AccountExists(i))
        
            string tpsAuth = DataAccessLayer.GetAuthCode(i.Pin);
            creditsFile.WriteLine(String.Format("01\t2:0.00", i.AuthCode, i.Pin, c.CreditAmount));
        
        else
        
            c.Error = true;
            c.ErrorMessage = "NO ACCOUNT";
        

        DataAccessLayer.AddCredit(c);

    

    creditsFile.Close();
    creditsFile.Dispose();

    string dest =  Path.Combine(Settings.CreditArchivePath, Path.GetFileName(creditFile));
    File.Move(creditFile,dest);
    //File.Delete(errorFile);

【问题讨论】:

是否有其他应用程序打开并锁定了文件?您可能也想检查一下。 DateTime.Now.ToString("MMddyy-hhmmss")你每秒创建多少个文件? @Dave,一天一个。该函数每天只调用一次。 检查防病毒扫描程序、索引服务器等 【参考方案1】:

是的,StreamReader.Dispose 关闭了底层流(用于创建流的所有公共方式)。但是,还有一个更好的选择:

using (TextReader reader = File.OpenText("file.txt"))


这有一个额外的好处,它打开底层流,提示 Windows 你将按顺序访问它。

这是一个测试应用程序,它显示了适合我的第一个版本。我并不是说这可以证明任何特别的事情 - 但我很想知道它对您的效果如何。

using System;
using System.IO;

class Program

    public static void Main(string[] args)
    
        for (int i=0; i < 1000; i++)
        
            using(StreamReader sr = new StreamReader
                  (File.Open("somefile.txt", FileMode.Open)))
            
                Console.WriteLine(sr.ReadLine());
            
            File.Move("somefile.txt", "somefile.bak");
            File.Move("somefile.bak", "somefile.txt");
        
    

如果可行,则表明这与您在阅读时所做的事情有关...

现在这里是您编辑的问题代码的缩短版本 - 即使在网络共享上,它对我来说也很好用。请注意,我已将 FileMode.Create 更改为 FileMode.CreateNew - 否则 可能 仍然有一个应用程序可以处理旧文件,可能。这对你有用吗?

using System;
using System.IO;

public class Test
    
    static void Main()
    
        StreamWriter creditsFile = new StreamWriter(File.Open("test.txt", 
                                          FileMode.CreateNew));

        creditsFile.WriteLine("code\\inc");

        creditsFile.Close();
        creditsFile.Dispose();

        File.Move("test.txt", "test2.txt");
    

【讨论】:

知道为什么我不能在第一个块中移动文件吗? 不——应该没问题。奇数。 第一个版本是否总是失败而第二个版本总是工作? 刚试了第一个版本,它在循环中为我工作了 20 次。 我已经用第一种方式编码了一百次,以前从来没有遇到过问题。现在我在 Windows 共享上打开文件,这是我可以解决问题的唯一方法。第一个示例每次都失败,而第二个示例每次都有效。所以我以为我做错了【参考方案2】:

注意 - 您的 using 块不需要嵌套在它们自己的块中 - 它们可以是连续的,如下所示:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
using(StreamReader sr = new StreamReader(fs))

    //read file

这种情况下的dispose顺序仍然和嵌套blocks一样(即StreamReader在这种情况下仍然会在FileStream之前dispose)。

【讨论】:

对我来说它看起来更好。 理解这与任何其他具有初始子句后跟语句的构造没有什么不同,其中语句可以是块。 (一个经典的例子是if (list != null) foreach (object item in list) ... ,它是一个嵌套在if 中的foreach。)具体来说,这个“嵌套”——并且是一种不理想的缩进样式,因为它确实不表示嵌套。如果除第一行之外的所有内容都缩进,那么会更清楚发生了什么:第二个“使用”嵌套在第一行中。【参考方案3】:

我会尝试使用FileInfo.Open()FileInfo.MoveTo() 而不是File.Open()File.Move()。您也可以尝试使用FileInfo.OpenText()。但这些只是建议。

【讨论】:

我会尝试 FileInfo 方法,但我认为在下面,它们只是对 File.Move 的调用 是的,但也许他们在内部处理流(由 FileInfo.Open() 创建)。此外,文档说他们只做一次安全检查,所以它可能会稍微快一点......【参考方案4】:

是否有可能其他东西锁定了 somefile.txt?

从本地(到文件)cmd 行的简单检查

net files

如果有其他东西有锁,可能会给你一些线索。

您也可以获取FileMon 之类的信息来获取更多详细信息,并检查您的应用是否正常发布。

【讨论】:

【参考方案5】:

由于这似乎不是编码问题,因此我将戴上我的 syadmin 帽子并提供一些建议。

    客户端或服务器上的病毒扫描程序在文件创建时对其进行扫描。 Windows opportunistic locking 习惯于搞砸网络共享。我记得这主要是具有平面文件数据库的多个读/写客户端的问题,但caching 肯定可以解释您的问题。 Windows file open cache。我不确定这在 Win2K 中是否仍然是一个问题,但 FileMon 会告诉你。

编辑:如果你能从服务器机器上捕捉到它,那么 Sysinternal 的句柄会告诉你它打开了什么。

【讨论】:

非常有趣。我过去在另一个我没有编码的应用程序中也遇到过问题,但我们发现罪魁祸首是 AVG。我得调查一下。

以上是关于using 子句会关闭此流吗?的主要内容,如果未能解决你的问题,请参考以下文章

sql中ON子句和using子句的区别

使用带有 N 查询的“USING”子句的雄辩连接

using 子句调用 Dispose 失败?

在 Oracle Merge 语句的 Using 子句中指定参数

SQL 异常在嵌套查询中使用“USING”子句?

LINQ 查询子句的顺序是不是会影响实体框架的性能?