C# 正在获取当前文件长度/FileInfo.length缓存和过时信息
我正在跟踪一个文件夹中的文件及其长度,至少有一个文件仍在写入 我必须对我用于其他目的的每个文件长度保持不断更新的记录C# 正在获取当前文件长度/FileInfo.length缓存和过时信息,c#,.net,file-io,C#,.net,File Io,我正在跟踪一个文件夹中的文件及其长度,至少有一个文件仍在写入 我必须对我用于其他目的的每个文件长度保持不断更新的记录 Update方法每15秒调用一次,如果文件长度与上次更新中确定的长度不同,则更新文件的属性 更新方法如下所示: var directoryInfo = new DirectoryInfo(archiveFolder); var archiveFiles = directoryInfo.GetFiles() .Orde
Update
方法每15秒调用一次,如果文件长度与上次更新中确定的长度不同,则更新文件的属性
更新方法如下所示:
var directoryInfo = new DirectoryInfo(archiveFolder);
var archiveFiles = directoryInfo.GetFiles()
.OrderByDescending(f=>f.CreationTimeUtc);
foreach (FileInfo fi in archiveFiles)
{
//check if file existed in previous update already
var origFileProps = cachedFiles.GetFileByName(fi.FullName);
if (origFileProps != null && fi.Length == origFileProps.EndOffset)
{
//file length is unchanged
}
else
{
//Update the properties of this file
//set EndOffset of the file to current file length
}
}
我知道,许多FileInfo
属性(包括Length
)都已预填充,只要在更新之间不进行缓存(缓存的信息不应超过15秒),就可以了
我假设每个DirectoryInfo.GetFiles()
调用都会生成一组新的FileInfos
,然后使用FindFirstFile
/FindNextFile
Win32 API将这些文件填充为新信息。但事实似乎并非如此
非常罕见,但最终我肯定会遇到这样的情况:写入的文件的文件长度每次有5、10甚至20分钟没有更新(如果有必要,测试是在Windows 2008 Server x64上完成的)
当前的解决方法是调用fi.Refresh()
强制更新每个文件信息。这似乎在内部委托给GetFileAttributesEx
Win32 API调用来更新文件信息
虽然强制手动刷新的成本是可以忍受的,但我更愿意理解为什么我首先会得到陈旧的信息。
FileInfo
信息是何时生成的,它与调用DirectoryInfo.GetFiles()
有何关系?下面是否有我没有完全掌握的文件I/O缓存层?我认为您应该使用并订阅已更改的事件。它在指定的文件系统项更改时触发。我同意Wojteq的观点,即使用FileSystemWatcher类将是更好的解决方案。当文件或目录的不同属性发生更改(例如他引用的更改事件)时,它会公开事件,这是一个比当前使用的轮询解决方案更好的解决方案。要回答您的问题,即为什么刷新需要不同的时间来反映文件大小的更改,答案是与Windows操作系统的底层虚拟内存管理器有关。当执行文件I/O时,它实际上会针对内存映射文件进行更新;这是由操作系统管理的文件的缓冲副本。因此,Windows控制何时将缓冲数据写入磁盘。无法预测特定的缓冲数据块何时会物理写入磁盘。这意味着更新文件流将把这些更新放在缓冲区中。如果要刷新()流,则缓冲更新应立即写入磁盘,如果关闭流,则将在流关闭后从缓冲区写入磁盘,如果流保持打开状态,则由Windows决定将缓冲数据写入磁盘。Raymond Chen现在已经就这个问题写了一篇非常详细的博客文章:
在NTFS中,文件系统元数据不是目录项的属性
而不是文件,将一些元数据复制到
目录项作为改进目录枚举的调整
性能。像Find-First-File这样的函数报告目录
条目,并通过放置胖用户习惯的元数据
获得“免费”,他们可以避免比脂肪更慢
目录列表目录枚举函数报告
上次更新的元数据,可能与实际元数据不一致
如果目录项过时。
从本质上讲,这取决于性能:从DirectoryInfo.GetFiles()
和FindFirstFile
/FindNextFile
Win32 API下面收集的目录信息出于性能原因被缓存,以保证在NTFS中比在旧FAT中获取目录信息的性能更好。只有直接调用文件上的Get-file-size()
才能获取准确的文件大小信息(在FileInfo
上的.NET调用Refresh()
或直接从文件名获取FileInfo
)-或打开和关闭文件流,导致更新的文件信息传播到目录元数据缓存。后一种情况解释了为什么写入过程关闭文件时会立即更新文件大小
这也解释了Windows 2003 Server中似乎没有出现此问题—当时文件信息的复制频率更高/每当刷新缓存时—Windows 2008 Server不再是这种情况:
至于多久一次,答案要复杂一点。从
Windows Vista(及其相应的Windows Server版本,我
不知道,但我相信你可以抬头看看,我说的“你”是指“玉红”
在以下情况下,NTFS文件系统将执行此礼貌复制:
文件对象的最后一个句柄已关闭NTFS的早期版本
每当缓存打开时,在文件打开时复制数据
脸红了,这意味着根据一项调查,这种情况经常发生
不可预测的时间表。这种变化的结果是
目录条目现在更新的频率较低,因此
上次更新的文件大小比以前更过时。
阅读全文内容丰富,值得推荐 缓冲将以秒(而不是分钟)的顺序解释更新延迟,写入代码是用C语言编写的,并使用
fwrite
,默认情况下使用buff