我正在用c#写一个程序,需要反复访问1个图像文件。大多数时候它是有效的,但如果我的计算机运行得很快,它会在文件保存回文件系统之前尝试访问该文件,并抛出一个错误:
文件正在被另一个进程使用
我想找到一个解决这个问题的方法,但我在谷歌上的所有搜索都只能通过使用异常处理来创建检查。这违背了我的宗教信仰,所以我想知道有没有更好的方法?
我正在用c#写一个程序,需要反复访问1个图像文件。大多数时候它是有效的,但如果我的计算机运行得很快,它会在文件保存回文件系统之前尝试访问该文件,并抛出一个错误:
文件正在被另一个进程使用
我想找到一个解决这个问题的方法,但我在谷歌上的所有搜索都只能通过使用异常处理来创建检查。这违背了我的宗教信仰,所以我想知道有没有更好的方法?
当前回答
下面是一些代码,据我所知,它与接受的答案相同,但代码更少:
public static bool IsFileLocked(string file)
{
try
{
using (var stream = File.OpenRead(file))
return false;
}
catch (IOException)
{
return true;
}
}
然而,我认为用以下方式来做会更稳健:
public static void TryToDoWithFileStream(string file, Action<FileStream> action,
int count, int msecTimeOut)
{
FileStream stream = null;
for (var i = 0; i < count; ++i)
{
try
{
stream = File.OpenRead(file);
break;
}
catch (IOException)
{
Thread.Sleep(msecTimeOut);
}
}
action(stream);
}
其他回答
你可以使用我的库来访问多个应用程序中的文件。
您可以从nuget: install - package Xabe安装它。FileLock
如果你想了解更多信息,请检查 https://github.com/tomaszzmuda/Xabe.FileLock
ILock fileLock = new FileLock(file);
if(fileLock.Acquire(TimeSpan.FromSeconds(15), true))
{
using(fileLock)
{
// file operations here
}
}
fileLock。Acquire方法仅当可以锁定该对象的文件独占时才返回true。 但是上传文件的应用程序也必须在文件锁中进行上传。 如果对象不可访问,方法返回false。
我最近遇到了这个问题,找到了这个: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.");
}
I once needed to upload PDFs to an online backup archive. But the backup would fail if the user had the file open in another program (such as PDF reader). In my haste, I attempted a few of the top answers in this thread but could not get them to work. What did work for me was trying to move the PDF file to its own directory. I found that this would fail if the file was open in another program, and if the move were successful there would be no restore-operation required as there would be if it were moved to a separate directory. I want to post my basic solution in case it may be useful for others' specific use cases.
string str_path_and_name = str_path + '\\' + str_filename;
FileInfo fInfo = new FileInfo(str_path_and_name);
bool open_elsewhere = false;
try
{
fInfo.MoveTo(str_path_and_name);
}
catch (Exception ex)
{
open_elsewhere = true;
}
if (open_elsewhere)
{
//handle case
}
我使用这个解决方案,但我有一个时间间隔,当我检查文件锁定与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函数在所有?
谢谢
我很有兴趣看看这是否会引发任何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的问题范围,即简单地检查文件是否在使用,但这确实是我到达这里时希望解决的问题,所以也许它对其他人有用。