2016-07-25 57 views
0

我想知道是否有办法创建文件并设置最后写入时间(和其他时间戳信息),而不允许另一个进程获取文件之间的锁定这两个操作。创建文件,然后设置时间戳而不释放文件锁定

我想这样做的原因是为了解决防病毒刚创建文件时获取文件锁定的问题,并且在文件属性尝试设置时仍然存在锁定问题。具体来说,我正在使用的代码是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

为什么*“不允许另一个进程获取文件之间的锁定”*?为什么你以后不能改变时间? – Sinatr

+0

听起来像反病毒软件攻击它,并防止修改? –

+0

您可以在fileStream.Dispose()后更改CreationTime。但不在两者之间。 – 2016-07-25 14:34:20

回答

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); 
     } 
    } 
} 
+0

完美。感谢你和@Damien_The_Unbeliever。 – flange

0

问题是你正在尝试访问你正在使用的语句正在使用的文件。这就是你遇到错误的原因。你需要完成你的使用语句,然后你可以在文件上分配创建时间。

如果文件被其他软件锁定,最好的办法是创建一个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); 
    } 
} 
+0

这会停止异常,但不能解决另一个进程在创建和设置属性之间获取锁定的问题。正如我在原文中所说的,我正在考虑重试,但想知道是否可以使用另一种不释放文件锁定的方法。 – flange

+0

是的,我明白你的目标是什么,但你必须先释放文件,然后才能使用不同的库重新打开它。 –

+0

您应该检查异常是由于文件被锁定:http://stackoverflow.com/a/11060322 –

0

没有,没有什么可以做,以阻止另一进程锁定的文件。

您可以尝试编写该文件的临时版本,然后使用Process.Start执行Robocopy复制文件,同时设置属性。该文件的原始副本变得无关紧要 - 您可以稍后清理它。

这将取决于Robocopy用于复制文件和设置属性的方法是否为原子。

有人已经编写了一个包装来避免从.NET代码中调用命令行应用程序的丑陋 - 它被称为RoboSharp并具有nuget package

+1

如果Robocopy是原子的,则原子性是可能的。如果原子性是可能的,那么推测在我的代码中有一种方法可以使用这种原子性。 – flange

+0

是的,它会使用一些较低级别的API。我想知道是否有已经打包的第三方库。现在我很好奇。我会看看......是的,有一个包裹RoboCopy的nuget包。 –

+0

但是,如果@aquinas的答案是有效的,那么这个解决方案就比较而言非常笨重和可疑。 –