我显然已经习惯了一个糟糕的编码习惯。以下是我一直在编写的代码示例:
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);
}
答案 0 :(得分:37)
是的,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");
}
}
答案 1 :(得分:11)
注意 - 你的使用块不需要嵌套在它们自己的块中 - 它们可以是顺序的,如:
using(FileStream fs = File.Open("somefile.txt", FileMode.Open))
using(StreamReader sr = new StreamReader(fs))
{
//read file
}
在这种情况下处理的顺序仍然与嵌套块相同(即,在这种情况下,StreamReader仍会在FileStream之前处置)。
答案 2 :(得分:1)
我会尝试使用FileInfo.Open()
和FileInfo.MoveTo()
代替File.Open()
和File.Move(
)。您也可以尝试使用FileInfo.OpenText()
。但这些只是建议。
答案 3 :(得分:0)
是否有其他东西可以锁定somefile.txt?
从本地(到文件)cmd行进行简单检查
net files
如果其他任何东西都有锁定,可能会给你一些线索。
或者,您可以获得FileMon之类的内容来获取更多详细信息,并检查您的应用是否正常发布。
答案 4 :(得分:0)
由于这似乎不是编码问题,我将打开我的syadmin帽子并提出一些建议。
编辑:如果你可以从服务器机器中捕获它,那么Sysinternal的Handle会告诉你它打开了什么。