创建文件然后设置时间戳而不释放文件锁

时间:2016-07-25 14:28:19

标签: c# .net windows file

我想知道是否有办法创建文件并设置上次写入时间(以及其他时间戳信息),而不允许其他进程在这两个操作之间获取对文件的锁定。

我想要这样做的原因是修复了一个问题,即防病毒在创建文件后立即获取锁定,并且在尝试设置文件属性时仍然具有锁定。具体来说,我正在使用的代码是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',因为它正由另一个进程使用。”

我正在考虑使用重试机制来实现时间属性的设置,但是想知道是否有更优雅的解决方案。

3 个答案:

答案 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