using子句会关闭此流吗?

我显然已经习惯了一个糟糕的编码习惯。 以下是我编写的代码示例:

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子句中遇到了问题,所以我把所有内容都扩展了,每次都无法复制。 我在这个方法调用中创建了文件,所以我认为其他任何文件都没有打开句柄。 我还validation了Path.Combine调用返回的字符串是否正确。

 private static void GenerateFiles(List 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("{0}{1}\t{2: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); } 

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

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

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

这是一个测试应用程序,显示第一个版本适合我。 我并不想说这是任何特别的证据 – 但我很想知道它对你有多好。

 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"); } } 

注意 – 您的使用块不需要嵌套在它们自己的块中 – 它们可以是顺序的,如:

 using(FileStream fs = File.Open("somefile.txt", FileMode.Open)) using(StreamReader sr = new StreamReader(fs)) { //read file } 

在这种情况下处理的顺序仍然与嵌套块相同(即,在这种情况下,StreamReader仍将在FileStream之前部署)。

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

有没有其他东西可以锁定somefile.txt的可能性?

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

 net files 

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

或者,您可以获得类似FileMon的内容以获取更多详细信息,并检查您的应用是否正确发布。

由于这似乎不是一个编码问题,我将打开我的syadmin帽子,并提出一些建议。

  1. 在创建文件时扫描文件的客户端或服务器上的病毒扫描程序。
  2. Windows 机会锁定习惯会搞砸网络共享。 我记得这主要是多个具有平面文件数据库的读/写客户端的问题,但缓存当然可以解释你的问题。
  3. Windows 文件打开缓存 。 我不确定这是否仍然是Win2K中的问题,但FileMon会告诉你。

编辑:如果您可以从服务器机器中捕获它,那么Sysinternal的Handle会告诉您它打开了什么。