在开发和维护网站时,经常需要确保测试客户端使用的是最新的JavaScript文件。然而,手动查看或删除浏览器缓存中的文件是一个繁琐且缓慢的过程。为了解决这个问题,开发了一个名为WebCacheTool的命令行工具,它可以帮助用户更方便、更快速地列出、查看和删除Internet Explorer浏览器缓存中的文件。本文将介绍这个工具的使用方法和实现细节。
请遵循Internet Explorer关于从浏览器缓存中提取任意或不熟悉的文件的风险警告。通常情况下,不应该将缓存中的文件复制到系统上的其他位置使用。
WebCacheTool是一个命令行工具,适用于开发者和系统管理员在批处理文件和脚本中使用。其语法如下:
WebCacheTool <command> <arguments>
除非另有说明,参数是区分大小写的。支持以下命令:
列出与给定模式匹配的缓存条目。模式是一个不区分大小写的.NET正则表达式。每个缓存条目提供的信息包括:
示例:
WebCacheTool ls http://www.example.com/example.html$
如果存在,列出特定命名的文件。
WebCacheTool ls \.example\.com
列出来自*.example.com的所有条目。
WebCacheTool ls \.example\.com.*\.gif$
列出来自*.example.com的.gif文件。
WebCacheTool ls \.js$
列出缓存中的.js文件。
WebCacheTool ls .
转储缓存的全部内容。
有关构建有用的路径表达式的更多信息,请参见MSDN文档中的.NET正则表达式语言。
底层的WinInet API(下面将更详细地讨论)还支持通过魔术字符串"Cookie:"和"Visited:"检索cookie和历史记录项:
WebCacheTool ls Cookie:
列出系统上的所有cookie。
WebCacheTool ls Cookie:.*\.example\.com
列出来自example.com域的cookie。
WebCacheTool ls Visited:
列出所有历史记录项。
列出一个或多个特定文件的详细信息。此功能不支持正则表达式模式,而是以更易读的格式打印与ls相同的信息。
示例:
WebCacheTool info http://www.example.com/example.html http://www.example.com/example.gif
如果找到,打印两个文件的详细信息。
WebCacheTool info "Cookie:john smith@www.example.com/"
打印来自www.example.com的john smith的cookie的详细信息。
如果找到,从缓存中删除特定文件或文件。
示例:
WebCacheTool rm http://www.example.com/example.html
将特定文件或文件的内容打印到标准输出。注意,应该只执行此命令以查看文本文件!
示例:
WebCacheTool cat http://www.example.com/example.html
打印简短的命令摘要。
WebCacheTool使用围绕文档化的WinInet API的托管包装器。不幸的是,这些API使用可变长度结构习惯用法,使得围绕它们制作托管包装器有些痛苦。因此,尽管可能会首先考虑将PInvoke声明包括类型为INTERNET_CACHE_ENTRY_INFO的参数,但实际上需要用IntPtr替换这些参数,以全局分配的缓冲区,并负责自己解包结构。当然,这也意味着必须自己管理全局分配的内存,而且正确地做到这一点会使代码变得混乱。这里有一个最简单的示例,GetUrlCacheEntryInfo API的包装器:
[DllImport("wininet.dll", SetLastError=true)]
private static extern bool GetUrlCacheEntryInfo(
string lpszUrlName,
IntPtr lpCacheEntryInfo,
out UInt32 lpdwCacheEntryInfoBufferSize);
public static INTERNET_CACHE_ENTRY_INFO GetUrlCacheEntryInfo(
string url)
{
IntPtr buffer = IntPtr.Zero;
UInt32 structSize;
bool apiResult = GetUrlCacheEntryInfo(url, buffer, out structSize);
CheckLastError(url, true);
try
{
buffer = Marshal.AllocHGlobal((int)structSize);
apiResult = GetUrlCacheEntryInfo(url, buffer, out structSize);
if (apiResult == true)
{
return (INTERNET_CACHE_ENTRY_INFO)Marshal.PtrToStructure(buffer, typeof(INTERNET_CACHE_ENTRY_INFO));
}
CheckLastError(url, false);
}
finally
{
if (buffer.ToInt32() > 0)
{
try { Marshal.FreeHGlobal(buffer); } catch {}
}
}
Debug.Assert(false, "We should either early-return or throw before we get here");
return new INTERNET_CACHE_ENTRY_INFO();
// Make the compiler happy even though we never expect this code to run.
}
这些API迫使处理的另一个方面是Windows FILETIME结构,这是在INTERNET_CACHE_ENTRY_INFO结构中公开最后访问、最后修改和到期时间的方式。.NET 1.x定义了System.Runtime.InteropServices.FILETIME(在.NET 2.0中为System.Runtime.InteropServices.ComTypes)来代替这个。.NET还提供了一个DateTime.FromFileTime工厂方法。不幸的是,由于它们错误地使用了有符号类型,发现.NET定义是有缺陷的。因此,定义了自己的FILETIME结构,用于互操作:
[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
public UInt32 dwLowDateTime;
public UInt32 dwHighDateTime;
}
以及Win32 API FileTimeToSystemTime和SystemTimeToTzSpecificLocalTime:
[DllImport("Kernel32.dll", SetLastError=true)]
public static extern long FileTimeToSystemTime(
ref FILETIME FileTime,
ref SYSTEMTIME SystemTime);
[DllImport("kernel32.dll", SetLastError=true)]
public static extern long SystemTimeToTzSpecificLocalTime(
IntPtr lpTimeZoneInformation,
ref SYSTEMTIME lpUniversalTime,
out SYSTEMTIME lpLocalTime);
现在有了一个强大的.NET FILETIME操作例程的替代品。请注意,日期和时间总是相对于当前的夏令时值解析的,原因在更详细地讨论。
.NET Framework 2.0升级,其中ls命令将匹配模式的结果,而不是收集它们以返回。这将减少内存消耗和延迟。请注意,实现了ls以期待这个特性——否则,会考虑违反命令设计原则,让命令本身处理输出。
控制ls命令输出格式的开关。
ls输出的排序选项。