Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正在获取当前文件长度/FileInfo.length缓存和过时信息_C#_.net_File Io - Fatal编程技术网

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