我想知道是否有办法创建文件并设置上次写入时间(以及其他时间戳信息),而不允许其他进程在这两个操作之间获取对文件的锁定。
我想要这样做的原因是修复了一个问题,即防病毒在创建文件后立即获取锁定,并且在尝试设置文件属性时仍然具有锁定。具体来说,我正在使用的代码是SevenZipSharp(据我所见,不再维护)。
重现此问题的代码是:
var filePath = "test.txt";
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
{
var bytes = Encoding.ASCII.GetBytes("Hello fail.");
fileStream.Write(bytes, 0, bytes.Length);
var fileInfo = new FileInfo(filePath);
fileInfo.CreationTime = DateTime.Now;
}
执行最后一个语句时会产生以下异常: System.IO.IOException “该进程无法访问文件'c:\ test.txt',因为它正由另一个进程使用。”
我正在考虑使用重试机制来实现时间属性的设置,但是想知道是否有更优雅的解决方案。
答案 0 :(得分:2)
正如@Damien_The_Unbeliever所提到的,你需要获取文件句柄。试试这个。
class Program {
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetFileTime(SafeFileHandle hFile, ref long lpCreationTime, ref long lpLastAccessTime, ref long lpLastWriteTime);
static void Main(string[] args) {
var filePath = "test.txt";
long when = DateTime.Now.AddDays(10).ToFileTime();
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite)) {
if (!SetFileTime(fileStream.SafeFileHandle, ref when, ref when, ref when)) {
throw new Win32Exception();
}
var bytes = Encoding.ASCII.GetBytes("Hello fail.");
fileStream.Write(bytes, 0, bytes.Length);
}
}
}
答案 1 :(得分:0)
问题是您正在尝试访问using语句正在使用的文件。这就是你收到错误的原因。您需要完成using语句,然后才能在文件上分配创建时间。
如果文件被其他软件锁定,最好的办法是创建一个等待文件的while循环。
尝试以下方法:
var filePath = "test.txt";
DateTime creationTime;
using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
{
var bytes = Encoding.ASCII.GetBytes("Hello fail.");
fileStream.Write(bytes, 0, bytes.Length);
creationTime = DateTime.Now;
}
int numTries = 0;
while (true)
{
++numTries;
try
{
// Attempt to open the file exclusively.
using (var fileInfo = new FileInfo(filePath))
{
// If we got this far the file is ready
fileInfo.CreationTime = creationTime;
break;
}
}
catch (Exception ex)
{
if (numTries > 10)
{
// Get out of it
Console.WriteLine("This joker still has your file, I'm out.");
break;
}
// Wait for the lock to be released
System.Threading.Thread.Sleep(500);
}
}
答案 2 :(得分:0)
不,您无法阻止其他进程锁定文件。
您可以尝试编写该文件的临时版本,然后使用Robocopy执行Process.Start
以在设置属性时复制文件。该文件的原始副本变得无关紧要 - 您可以稍后清理它。
这将取决于Robocopy用于复制文件的方法和设置属性是否为原子。
有人已经编写了一个包装器,以避免从.NET代码调用命令行应用程序的丑陋 - 它被称为RoboSharp并且有一个nuget package。