如果你在代碼中使用了 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.Exists
和 File.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),不得用於商業目的,基於本文修改后的作品務必以相同的許可發布。如有任何疑問,請與我聯系。