我正在用c#写一个程序,需要反复访问1个图像文件。大多数时候它是有效的,但如果我的计算机运行得很快,它会在文件保存回文件系统之前尝试访问该文件,并抛出一个错误:
文件正在被另一个进程使用
我想找到一个解决这个问题的方法,但我在谷歌上的所有搜索都只能通过使用异常处理来创建检查。这违背了我的宗教信仰,所以我想知道有没有更好的方法?
我正在用c#写一个程序,需要反复访问1个图像文件。大多数时候它是有效的,但如果我的计算机运行得很快,它会在文件保存回文件系统之前尝试访问该文件,并抛出一个错误:
文件正在被另一个进程使用
我想找到一个解决这个问题的方法,但我在谷歌上的所有搜索都只能通过使用异常处理来创建检查。这违背了我的宗教信仰,所以我想知道有没有更好的方法?
当前回答
这样的东西会有用吗?
var fileWasWrittenSuccessfully = false;
while (fileWasWrittenSuccessfully == false)
{
try
{
lock (new Object())
{
using (StreamWriter streamWriter = new StreamWriter("filepath.txt"), true))
{
streamWriter.WriteLine("text");
}
}
fileWasWrittenSuccessfully = true;
}
catch (Exception)
{
}
}
其他回答
除了工作3-liner,只是为了参考:如果你想要完整的信息-在微软开发中心有一个小项目:
https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4
现发现于: https://github.com/TacticalHorse/LockFinder/blob/master/LockFinder.cs
引言:
The C# sample code developed in .NET Framework 4.0 would help in finding out which is the process that is having a lock on a file. RmStartSession function which is included in rstrtmgr.dll has been used to create a restart manager session and according to the return result a new instance of Win32Exception object is created. After registering the resources to a Restart Manager session via RmRegisterRescources function, RmGetList function is invoked to check what are the applications are using a particular file by enumerating the RM_PROCESS_INFO array.
它通过连接到“重启管理器会话”来工作。
重启管理器使用向会话注册的资源列表 确定哪些应用程序和服务必须关闭并重新启动。 资源可以通过文件名、服务短名称或 描述正在运行的应用程序的RM_UNIQUE_PROCESS结构。
为了满足你的特殊需求,它可能有点过度设计了…… 但如果这是你想要的,那就去拿vs-project吧。
我使用这个解决方案,但我有一个时间间隔,当我检查文件锁定与isfilellocked函数和当我打开文件。在这个时间跨度内,其他线程可以打开这个文件,所以我将得到IOException。
因此,我为此添加了额外的代码。在我的情况下,我想加载XDocument:
XDocument xDoc = null;
while (xDoc == null)
{
while (IsFileBeingUsed(_interactionXMLPath))
{
Logger.WriteMessage(Logger.LogPrioritet.Warning, "Deserialize can not open XML file. is being used by another process. wait...");
Thread.Sleep(100);
}
try
{
xDoc = XDocument.Load(_interactionXMLPath);
}
catch
{
Logger.WriteMessage(Logger.LogPrioritet.Error, "Load working!!!!!");
}
}
你怎么看?我能改点东西吗?也许我没有使用IsFileBeingUsed函数在所有?
谢谢
我最近遇到了这个问题,找到了这个:https://learn.microsoft.com/en-us/dotnet/standard/io/handling-io-errors。
在这里,微软描述了以下检查IOException是否由于锁定文件导致的方法:
catch (IOException e) when ((e.HResult & 0x0000FFFF) == 32 ) {
Console.WriteLine("There is a sharing violation.");
}
static bool FileInUse(string path)
{
try
{
using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
{
fs.CanWrite
}
return false;
}
catch (IOException ex)
{
return true;
}
}
string filePath = "C:\\Documents And Settings\\yourfilename";
bool isFileInUse;
isFileInUse = FileInUse(filePath);
// Then you can do some checking
if (isFileInUse)
Console.WriteLine("File is in use");
else
Console.WriteLine("File is not in use");
希望这能有所帮助!
我很有兴趣看看这是否会引发任何WTF反射。我有一个进程,它创建并随后从控制台应用程序启动PDF文档。然而,我正在处理一个弱点,如果用户要多次运行该进程,生成相同的文件而不首先关闭先前生成的文件,应用程序将抛出异常并死亡。这是一个相当常见的情况,因为文件名是基于销售报价数字的。
与其以这种不体面的方式失败,我决定依靠自动递增的文件版本控制:
private static string WriteFileToDisk(byte[] data, string fileName, int version = 0)
{
try
{
var versionExtension = version > 0 ? $"_{version:000}" : string.Empty;
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"{fileName}{versionExtension}.pdf");
using (var writer = new FileStream(filePath, FileMode.Create))
{
writer.Write(data, 0, data.Length);
}
return filePath;
}
catch (IOException)
{
return WriteFileToDisk(data, fileName, ++version);
}
}
可能需要对catch块多加注意,以确保捕获了正确的IOException(s)。我可能还会在启动时清除应用程序存储,因为这些文件是临时的。
我意识到这超出了OP的问题范围,即简单地检查文件是否在使用,但这确实是我到达这里时希望解决的问题,所以也许它对其他人有用。