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帽子,并提出一些建议。
- 在创建文件时扫描文件的客户端或服务器上的病毒扫描程序。
- Windows 机会锁定习惯会搞砸网络共享。 我记得这主要是多个具有平面文件数据库的读/写客户端的问题,但缓存当然可以解释你的问题。
- Windows 文件打开缓存 。 我不确定这是否仍然是Win2K中的问题,但FileMon会告诉你。
编辑:如果您可以从服务器机器中捕获它,那么Sysinternal的Handle会告诉您它打开了什么。