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
子句显式调用了 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(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("{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);
}
I've apparently worked myself into a bad coding habit. Here is an example of the code I've been writing:
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
I thought that because the using
clause explicitly called Close()
and Dispose()
on the StreamReader
that the FileStream
would be closed as well.
The only way I could fix the problem I was having was by changing the above block to this:
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
Should closing the StreamReader
by disposing in the first block also close the underlying FileStream
? Or, was I mistaken?
Edit
I decided to post the actual offending block of code, to see if we can get to the bottom of this. I am just curious now.
I thought I had a problem in the using
clause, so I expanded everything out, and it still can't copy, every time. I create the file in this method call, so I don't think anything else has a handle open on the file. I've also verified that the strings returned from the Path.Combine
calls are correct.
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("{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);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
是的,
StreamReader.Dispose
关闭底层流(对于创建流的所有公共方式)。 不过,还有一个更好的替代方案:这还有一个额外的好处,即它会打开底层流,并向 Windows 提示您将按顺序访问它。
这是一个测试应用程序,它显示了对我有用的第一个版本。 我并不是想说这是任何特别的证据 - 但我很想知道它对你有多有效。
如果有效,则表明这与您在阅读时所做的事情有关...
现在这是您编辑的问题代码的缩短版本 - 即使在网络共享上,它也对我来说效果很好。 请注意,我已将
FileMode.Create
更改为FileMode.CreateNew
- 否则可能仍然有一个带有旧版本句柄的应用程序文件,可能。 这对你有用吗?Yes,
StreamReader.Dispose
closes the underlying stream (for all public ways of creating one). However, there's a nicer alternative:This has the added benefit that it opens the underlying stream with a hint to Windows that you'll be accessing it sequentially.
Here's a test app which shows the first version working for me. I'm not trying to say that's proof of anything in particular - but I'd love to know how well it works for you.
If that works, it suggests that it's something to do with what you do while reading...
And now here's a shortened version of your edited question code - which again works fine for me, even on a network share. Note that I've changed
FileMode.Create
toFileMode.CreateNew
- as otherwise there could still have been an app with a handle on the old file, potentially. Does this work for you?注意 - 您的 using 块不需要嵌套在它们自己的块中 - 它们可以是连续的,如下所示:
在这种情况下的处置顺序仍然与嵌套块相同(即, StreamReader 仍将在 FileStream 之前处置在这种情况下)。
Note - your using blocks do not need to be nested in their own blocks - they can be sequential, as in:
The order of disposal in this case is still the same as the nested blocks (ie, the StreamReader will still dispose before the FileStream in this case).
我会尝试使用
FileInfo.Open()
和FileInfo.MoveTo()
而不是File.Open()
和File。移动(
)。 您还可以尝试使用FileInfo.OpenText()
。 但这些只是建议。I would try to use
FileInfo.Open()
andFileInfo.MoveTo()
instead ofFile.Open()
andFile.Move(
). You could also try to useFileInfo.OpenText()
. But these are just suggestions.是否有可能其他东西锁定了 somefile.txt?
从本地(到文件)命令行进行简单的检查
可能会为您提供一些线索,看看是否有其他东西有锁。
或者,您可以使用 FileMon 来获取更多详细信息,并且检查您的应用程序是否正常发布。
Is there any possibility that something else has a lock to somefile.txt?
A simple check from a local (to the file) cmd line
may well give you some clues if anything else has a lock.
Alternatively you can get something like FileMon to take even more details, and check that your app is releasing properly.
由于这似乎不是一个编码问题,因此我将戴上我的系统管理员帽子并提供一些建议。
编辑:如果您可以从服务器计算机实时捕获它,那么 Sysinternal 的句柄将告诉您它打开了什么。
Since this doesn't seem to be a coding issue, I'm going to put my syadmin hat on and offer a few suggestions.
Edit: If you can catch it in the act from the server machine, then Sysinternal's Handle will tell you what has it open.