我显然已经习惯了一个糟糕的编码习惯.这是我写的代码示例:
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
条款明确要求Close()
,并Dispose()
在StreamReader
该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(Listcredits) { 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); }
Jon Skeet.. 39
是的,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"); } }
Not Sure.. 11
注意 - 您的使用块不需要嵌套在它们自己的块中 - 它们可以是顺序的,如:
using(FileStream fs = File.Open("somefile.txt", FileMode.Open)) using(StreamReader sr = new StreamReader(fs)) { //read file }
在这种情况下处理的顺序仍然与嵌套块相同(即,在这种情况下,StreamReader仍将在FileStream之前部署).
是的,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之前部署).