我正在跟踪一个文件夹及其文件长度,至少其中一个文件仍在写入。
我必须不断更新我用于其他目的的每个文件长度的记录。
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
}
}
我知道 DirectoryInfo.GetFiles()正在预填充许多 FileInfo 属性,包括 Length - 只要在 更新之间不进行缓存,这是可以的(缓存的信息应该不得超过 15 秒)。
我假设每个 DirectoryInfo.GetFiles() 调用都会生成一组新 FileInfos,所有这些都填充了新信息然后使用 FindFirstFile/FindNextFile Win32 API。但事实并非如此。
很少,但最终我肯定会遇到这样的情况,即正在写入的文件的文件长度一次没有更新 5、10 甚至 20 分钟(测试是在 Windows 2008 Server x64 上完成的,如果这很重要)。
当前的解决方法是调用 fi.Refresh() 以强制更新每个文件信息。这在内部似乎委托(delegate)给 GetFileAttributesEx Win32 API 调用来更新文件信息。
虽然手动强制刷新的成本是可以容忍的,但我宁愿理解为什么我首先得到的是陈旧的信息。 FileInfo 信息何时生成,它与 DirectoryInfo.GetFiles() 的调用有何关系?是否有我没有完全掌握的文件 I/O 缓存层?
最佳答案
Raymond Chen 现在就这个问题写了一篇非常详细的博文:
Why is the file size reported incorrectly for files that are still being written to?
In NTFS, file system metadata is a property not of the directory entry but rather of the file, with some of the metadata replicated into the directory entry as a tweak to improve directory enumeration performance. Functions like FindFirstFile report the directory entry, and by putting the metadata that FAT users were accustomed to getting "for free", they could avoid being slower than FAT for directory listings. The directory-enumeration functions report the last-updated metadata, which may not correspond to the actual metadata if the directory entry is stale.
本质上它归结为性能:从 DirectoryInfo.GetFiles() 和 FindFirstFile/FindNextFile 下面的 Win32 API 收集的目录信息是出于性能原因缓存以保证在 NTFS 中比在旧 FAT 中获取目录信息有更好的性能。准确的文件大小信息只能通过直接在文件上调用 GetFileSize() 来获取(在 .NET 中调用 FileInfo 上的 Refresh() 或直接从文件名获取 FileInfo) - 或者打开和关闭文件流,这会导致更新的文件信息传播到目录元数据缓存。后一种情况解释了为什么在写入进程关闭文件时文件大小会立即更新。
这也解释了该问题似乎并未出现在 Windows 2003 Server 中 - 当时文件信息被更频繁地复制/每当缓存被刷新时 - Windows 2008 Server 不再是这种情况:
As for how often, the answer is a little more complicated. Starting in Windows Vista (and its corresponding Windows Server version which I don't know but I'm sure you can look up, and by "you" I mean "Yuhong Bao"), the NTFS file system performs this courtesy replication when the last handle to a file object is closed. Earlier versions of NTFS replicated the data while the file was open whenever the cache was flushed, which meant that it happened every so often according to an unpredictable schedule. The result of this change is that the directory entry now gets updated less frequently, and therefore the last-updated file size is more out-of-date than it already was.
阅读全文内容丰富,值得推荐!
关于c# - 获取当前文件长度/FileInfo.Length 缓存和陈旧信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7828132/
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i