IE 快取資料夾 (Temporary Internet Files) 不是一般檔案系統結構,Explorer 透過 index.dat 索引呈現虛擬檢視。直接用 Directory.GetFiles 只能看到 desktop.ini。必須呼叫 WinInet API 遍歷快取條目。
| 函數 | 用途 |
|---|---|
FindFirstUrlCacheEntry | 開始列舉,回傳枚舉控制碼 |
FindNextUrlCacheEntry | 取得下一個快取條目 |
FindCloseUrlCache | 關閉枚舉控制碼 |
FileTimeToSystemTime | (kernel32) FILETIME 轉 SYSTEMTIME |
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct INTERNET_CACHE_ENTRY_INFO
{
public int dwStructSize;
public IntPtr lpszSourceUrlName; // 來源 URL
public IntPtr lpszLocalFileName; // 本地檔案路徑
public int CacheEntryType; // 快取類型
public int dwUseCount; // 使用計數
public int dwHitRate; // 命中率
public int dwSizeLow; // 檔案大小低 32 位
public int dwSizeHigh; // 檔案大小高 32 位
public FILETIME LastModifiedTime; // 最後修改時間
public FILETIME ExpireTime; // 過期時間
public FILETIME LastAccessTime; // 最後存取時間
public FILETIME LastSyncTime; // 最後同步時間
public IntPtr lpHeaderInfo; // 標頭資訊
public int dwHeaderInfoSize;
public IntPtr lpszFileExtension; // 副檔名
public int dwExemptDelta;
}
[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
public uint dwLowDateTime;
public uint dwHighDateTime;
}
[StructLayout(LayoutKind.Sequential)]
public struct SYSTEMTIME
{
public short wYear, wMonth, wDayOfWeek, wDay, wHour, wMinute, wSecond, wMilliseconds;
}
public static class WinInet
{
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern IntPtr FindFirstUrlCacheEntry(
string lpszUrlSearchPattern,
IntPtr lpFirstCacheEntryInfo,
ref int lpdwFirstCacheEntryInfoBufferSize);
[DllImport("wininet.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool FindNextUrlCacheEntry(
IntPtr hEnumHandle,
IntPtr lpNextCacheEntryInfo,
ref int lpdwNextCacheEntryInfoBufferSize);
[DllImport("wininet.dll")]
public static extern bool FindCloseUrlCache(IntPtr hEnumHandle);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool FileTimeToSystemTime(
ref FILETIME lpFileTime,
out SYSTEMTIME lpSystemTime);
}
public class IeCacheReader
{
private const int ERROR_NO_MORE_ITEMS = 259;
public void EnumerateCache(Action onEntry)
{
int bufferSize = 0;
// 第一次呼叫取得所需緩衝區大小
IntPtr enumHandle = WinInet.FindFirstUrlCacheEntry(null, IntPtr.Zero, ref bufferSize);
int err = Marshal.GetLastWin32Error();
if (err == ERROR_NO_MORE_ITEMS) return; // 快取為空
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
try
{
enumHandle = WinInet.FindFirstUrlCacheEntry(null, buffer, ref bufferSize);
if (enumHandle == IntPtr.Zero) throw new System.ComponentModel.Win32Exception();
while (true)
{
var entry = (INTERNET_CACHE_ENTRY_INFO)Marshal.PtrToStructure(buffer, typeof(INTERNET_CACHE_ENTRY_INFO));
string url = Marshal.PtrToStringAuto(entry.lpszSourceUrlName);
string localFile = Marshal.PtrToStringAuto(entry.lpszLocalFileName);
long size = ((long)entry.dwSizeHigh << 32) | (uint)entry.dwSizeLow;
DateTime lastAccess = FileTimeToDateTime(entry.LastAccessTime);
onEntry(url, localFile, lastAccess, size);
bufferSize = bufferSize; // 重置
bool hasNext = WinInet.FindNextUrlCacheEntry(enumHandle, buffer, ref bufferSize);
if (!hasNext)
{
err = Marshal.GetLastWin32Error();
if (err == ERROR_NO_MORE_ITEMS) break;
if (err == 122) // ERROR_INSUFFICIENT_BUFFER
{
buffer = Marshal.ReAllocHGlobal(buffer, (IntPtr)bufferSize);
continue;
}
throw new System.ComponentModel.Win32Exception(err);
}
}
}
finally
{
WinInet.FindCloseUrlCache(enumHandle);
Marshal.FreeHGlobal(buffer);
}
}
private DateTime FileTimeToDateTime(FILETIME ft)
{
WinInet.FileTimeToSystemTime(ref ft, out SYSTEMTIME st);
return new DateTime(st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
}
}
// 使用範例
var reader = new IeCacheReader();
reader.EnumerateCache((url, file, time, size) =>
{
Console.WriteLine($"URL: {url}\nFile: {file}\nTime: {time}\nSize: {size}\n---");
});
wininet.dll,僅限 Windows 平台。WebCacheV01.dat),此 API 可能不完整支援。HttpClient + 自訂快取,而非依賴 IE 快取。NuGet 套件 WinInet.Interop 或 Microsoft.Win32.Interop 提供更完整的 managed 封裝,減少手寫 P/Invoke 錯誤。