謹慎使用 FileInfo.Exists 實例方法,而是使用 File.Exists 靜態方法替代


如果你在代碼中使用了 FileInfo.Exists 實例方法來判斷一個文件是否存在,也許會發現此方法可能錯誤地判斷來一個文件是否真的存在。這是一個坑。

本文將介紹坑的原因,並提供填坑的辦法。


 

 

問題代碼

我們使用兩種不同的方式判斷文件是否存在:

  • FileInfo.Exists 實例方法
  • File.Exists 靜態方法
static async Task Main(string[] args)
{
    var filePath = @"C:\Users\lvyi\Desktop\walterlv.log";
    var fileInfo = new FileInfo(filePath);
    while (true)
    {
        Console.WriteLine($"FileInfo.Exists = {fileInfo.Exists}");
        Console.WriteLine($" File.Exists = {File.Exists(filePath)}");
        Console.WriteLine("----");
        await Task.Delay(1000);
    }
}

現在運行這個程序,我們會發現,中途刪除了 walterlv.log 文件之后,FileInfo.Exists 依然返回了 true,而 File.Exists 已經開始返回 false 了。

以上代碼的運行結果

原因分析

實際翻閱代碼可以發現,FileInfo.ExistsFile.Exists 方法最終都是使用相同的方法來完成文件存在與否的判斷。

這是 FileInfo.Exists 的判斷:

public override bool Exists
{
    [SecuritySafeCritical] get
    {
        try
        {
            if (this._dataInitialised == -1)
                this.Refresh();
            if (this._dataInitialised != 0)
                return false;
            return (this._data.fileAttributes & 16) == 0;
        }
        catch
        {
            return false;
        }
    }
}

這是 File.Exists 的最終判斷:

public static bool FileExists(string fullPath)
{
    Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA data = new Interop.Kernel32.WIN32_FILE_ATTRIBUTE_DATA();
    int errorCode = FillAttributeInfo(fullPath, ref data, returnErrorOnNotFound: true);

    return (errorCode == 0) && (data.dwFileAttributes != -1)
            && ((data.dwFileAttributes & Interop.Kernel32.FileAttributes.FILE_ATTRIBUTE_DIRECTORY) == 0);
}

只不過,FileInfo.Exists 只會在沒有初始化的時候初始化一次,而 File.Exists 是沒有緩存的,每次都是直接去獲取文件的屬性(這就涉及到 IO)。

解決辦法

所以,如果你正在處理的文件在不同的時間可能存在也可能不存在,那么最好使用 File.Exists 來判斷文件存在與否,而不是使用 FileInfo.Exists 來判斷。

不過,如果你需要一次性判斷文件的非常多的信息(而不只是文件存在與否),那么依然建議使用 FileInfo,只不過在使用之前需要調用 Refresh 進行一次刷新。


我的博客會首發於 https://walterlv.com/,而 CSDN 和博客園僅從其中摘選發布,而且一旦發布了就不再更新。

知識共享許可協議

本作品采用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名呂毅(包含鏈接:https://blog.csdn.net/wpwalter),不得用於商業目的,基於本文修改后的作品務必以相同的許可發布。如有任何疑問,請與我聯系


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM