Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/297.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 有没有办法检查文件是否正在使用?_C#_.net_File_File Io_File Locking - Fatal编程技术网

C# 有没有办法检查文件是否正在使用?

C# 有没有办法检查文件是否正在使用?,c#,.net,file,file-io,file-locking,C#,.net,File,File Io,File Locking,我正在用C语言编写一个程序,需要反复访问一个图像文件。大多数情况下它都能工作,但如果我的计算机运行得很快,它会在文件被保存回文件系统之前尝试访问该文件并抛出错误: “另一进程正在使用的文件” 我想找到一种方法来解决这个问题,但我所有的谷歌搜索都只能通过使用异常处理来创建检查。这与我的宗教信仰背道而驰,所以我想知道是否有人有更好的方法来做这件事?我知道的唯一方法是使用Win32独占锁API,它速度不太快,但有一些例子 大多数人,为了简单地解决这个问题,只需尝试/catch/sleep循环。也许你可

我正在用C语言编写一个程序,需要反复访问一个图像文件。大多数情况下它都能工作,但如果我的计算机运行得很快,它会在文件被保存回文件系统之前尝试访问该文件并抛出错误:

“另一进程正在使用的文件”


我想找到一种方法来解决这个问题,但我所有的谷歌搜索都只能通过使用异常处理来创建检查。这与我的宗教信仰背道而驰,所以我想知道是否有人有更好的方法来做这件事?

我知道的唯一方法是使用Win32独占锁API,它速度不太快,但有一些例子

大多数人,为了简单地解决这个问题,只需尝试/catch/sleep循环。

也许你可以使用一个新的方法来观察更改的事件


我自己没用过这个,但可能值得一试。如果filesystemwatcher在这种情况下有点沉重,我会选择try/catch/sleep循环。

在这种情况下,您可能会遇到线程争用情况,有文档记录的例子表明这种情况被用作安全漏洞。如果您检查该文件是否可用,然后尝试使用它,您可能会在该点抛出该文件,恶意用户可能会利用该文件在代码中强制和利用该文件

您最好的选择是尝试获取文件句柄的try-catch/finally

try
{
   using (Stream stream = new FileStream("MyFilename.txt", FileMode.Open))
   {
        // File/Stream manipulating code here
   }
} catch {
  //check here why it failed and ask user to retry if the file is in use.
}

尝试将文件移动/复制到临时目录。如果可以,它没有锁,您可以安全地在temp dir中工作,而无需获得锁。否则,请在x秒内再次尝试移动它。

更新了此解决方案的说明:检查
FileAccess。只读文件的ReadWrite
将失败,因此该解决方案已修改为检查
FileAccess.Read

原件: 在过去的几年里,我一直在使用这段代码,我没有遇到任何问题

理解您对使用异常的犹豫,但您不能一直避免它们:

protected virtual bool IsFileLocked(FileInfo file)
{
    try
    {
        using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
        {
            stream.Close();
        }
    }
    catch (IOException)
    {
        //the file is unavailable because it is:
        //still being written to
        //or being processed by another thread
        //or does not exist (has already been processed)
        return true;
    }

    //file is not locked
    return false;
}

希望这有帮助

我使用此解决方法,但在使用IsFileLocked函数检查文件锁定和打开文件之间有一个时间间隔。在此时间跨度内,其他线程可以打开该文件,因此我将获得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函数


谢谢

使用此选项检查文件是否已锁定:

using System.IO;
using System.Runtime.InteropServices;
internal static class Helper
{
const int ERROR_SHARING_VIOLATION = 32;
const int ERROR_LOCK_VIOLATION = 33;

private static bool IsFileLocked(Exception exception)
{
    int errorCode = Marshal.GetHRForException(exception) & ((1 << 16) - 1);
    return errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION;
}

internal static bool CanReadFile(string filePath)
{
    //Try-Catch so we dont crash the program and can check the exception
    try {
        //The "using" is important because FileStream implements IDisposable and
        //"using" will avoid a heap exhaustion situation when too many handles  
        //are left undisposed.
        using (FileStream fileStream = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) {
            if (fileStream != null) fileStream.Close();  //This line is me being overly cautious, fileStream will never be null unless an exception occurs... and I know the "using" does it but its helpful to be explicit - especially when we encounter errors - at least for me anyway!
        }
    }
    catch (IOException ex) {
        //THE FUNKY MAGIC - TO SEE IF THIS FILE REALLY IS LOCKED!!!
        if (IsFileLocked(ex)) {
            // do something, eg File.Copy or present the user with a MsgBox - I do not recommend Killing the process that is locking the file
            return false;
        }
    }
    finally
    { }
    return true;
}
}
你自己试试看:

byte[] output1 = Helper.ReadFileBytes(@"c:\temp\test.txt");
string output2 = Helper.ReadFileTextWithEncoding(@"c:\temp\test.txt");
string output3 = Helper.ReadFileTextNoEncoding(@"c:\temp\test.txt");

根据我的经验,您通常希望这样做,然后“保护”您的文件来做一些有趣的事情,然后使用“保护”文件。如果您只有一个文件想要像这样使用,您可以使用Jeremy Thompson在回答中解释的技巧。然而,如果你试图在很多文件上这样做(例如,当你编写安装程序时),你会受到相当大的伤害

解决这个问题的一个非常优雅的方法是,如果文件系统中有一个文件正在使用,那么它将不允许您更改文件夹名称。将文件夹保存在同一个文件系统中,它将像一个符咒一样工作

请注意,您应该了解利用此漏洞的明显方式。毕竟,这些文件不会被锁定。另外,请注意,还有其他原因可能导致
移动操作失败。显然,正确的错误处理(MSDN)可以在这里提供帮助

var originalFolder = @"c:\myHugeCollectionOfFiles"; // your folder name here
var someFolder = Path.Combine(originalFolder, "..", Guid.NewGuid().ToString("N"));

try
{
    Directory.Move(originalFolder, someFolder);

    // Use files
}
catch // TODO: proper exception handling
{
    // Inform user, take action
}
finally
{
    Directory.Move(someFolder, originalFolder);
}

对于单个文件,我坚持Jeremy Thompson发布的锁定建议。

只需按预期使用异常即可。接受该文件正在使用,然后重试,直到操作完成。这也是最有效的,因为在执行操作之前不会浪费任何周期来检查状态

例如,使用下面的函数

TimeoutFileAction(() => { System.IO.File.etc...; return null; } );
2秒后超时的可重用方法

private T TimeoutFileAction<T>(Func<T> func)
{
    var started = DateTime.UtcNow;
    while ((DateTime.UtcNow - started).TotalMilliseconds < 2000)
    {
        try
        {
            return func();                    
        }
        catch (System.IO.IOException exception)
        {
            //ignore, or log somewhere if you want to
        }
    }
    return default(T);
}
private T TimeoutFileAction(Func Func)
{
var start=DateTime.UtcNow;
while((DateTime.UtcNow-started).total毫秒<2000)
{
尝试
{
返回func();
}
捕获(System.IO.IOException异常)
{
//忽略,或者如果你想登录的话
}
}
返回默认值(T);
}

上述公认的答案存在一个问题,即如果文件已使用FileShare.Read模式打开以进行写入,或者如果文件具有只读属性,则代码将无法工作。此修改后的解决方案工作最可靠,需要记住两件事(对于已接受的解决方案也是如此):

  • 它不适用于以写共享模式打开的文件
  • 这不考虑线程问题,因此您需要将其锁定或单独处理线程问题
  • 请记住上述内容,这将检查文件是锁定写入还是锁定防止读取:


    您可以返回一个任务,该任务在可用时立即为您提供一个流。这是一个简化的解决方案,但它是一个很好的起点。它是线程安全的

    private async Task<Stream> GetStreamAsync()
    {
        try
        {
            return new FileStream("sample.mp3", FileMode.Open, FileAccess.Write);
        }
        catch (IOException)
        {
            await Task.Delay(TimeSpan.FromSeconds(1));
            return await GetStreamAsync();
        }
    }
    

    以下是一些代码,据我所知,它们与公认的答案具有相同的功能,但代码较少:

        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);
        }
    
    public static void TryToDoWithFileStream(字符串文件、操作、,
    整数计数,整数msecTimeOut)
    {
    FileStream=null;
    对于(变量i=0;i
    您可以使用我的库从多个应用程序访问文件

    您可以从nuget:install包Xabe.FileLock安装它

    如果您想了解更多信息,请检查

    仅当可以锁定此对象的独占文件时,fileLock.Acquire方法才会返回true。 但是app-wh
    private async Task<Stream> GetStreamAsync()
    {
        try
        {
            return new FileStream("sample.mp3", FileMode.Open, FileAccess.Write);
        }
        catch (IOException)
        {
            await Task.Delay(TimeSpan.FromSeconds(1));
            return await GetStreamAsync();
        }
    }
    
    using (var stream = await FileStreamGetter.GetStreamAsync())
    {
        Console.WriteLine(stream.Length);
    }
    
        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);
        }
    
    ILock fileLock = new FileLock(file);
    if(fileLock.Acquire(TimeSpan.FromSeconds(15), true))
    {
        using(fileLock)
        {
            // file operations here
        }
    }
    
    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);
        }
    }
    
    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)
        {
    
        }
    }
    
    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
    }
    
    retry_possibility:
    //somecode here
    
    try
    {
        using(FileStream stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None))
        {
            stream.Close();
        }
        //write or open your file here
    }
    catch (IOException)
    {
        DialogResult dialogResult = MessageBox.Show("This file is opened by you or another user. Please close it and press retry.\n"+ expFilePath, "File Locked", MessageBoxButtons.RetryCancel);
        if (dialogResult == DialogResult.Retry)
        {
            goto retry_possibility;
        }
        else if (dialogResult == DialogResult.Cancel)
        {
            //do nothing
        }
    }