文件资源管理器打开时如何修改目录时间戳?

时间:2017-09-05 15:23:31

标签: c# file directory timestamp ioexception

我的应用程序全年创建文件和目录,需要访问这些目录的时间戳,以确定是否需要创建另一个目录。因此,当我移动目录时,我保留其时间戳是至关重要的。当Directory.Move()不可选时(例如移动到其他驱动器时),我可以这样做。

    FileSystem.CopyDirectory(sourcePath, targetPath, overwrite);

    Directory.SetCreationTimeUtc  (targetPath, Directory.GetCreationTimeUtc  (sourcePath));
    Directory.SetLastAccessTimeUtc(targetPath, Directory.GetLastAccessTimeUtc(sourcePath));
    Directory.SetLastWriteTimeUtc (targetPath, Directory.GetLastWriteTimeUtc (sourcePath));

    Directory.Delete(sourcePath, true);

但是,如果文件资源管理器处于打开状态,则所有这三个“Directory.Set”方法都会失败,并且看起来这个目录是否当前在文件资源管理器中可见也无关紧要(编辑:我怀疑这与快速访问有关,但原因并不是特别重要)。它会抛出一个IOException,表示“进程无法访问文件'C:\ MyFolder',因为它正由另一个进程使用。”

我应该如何处理?是否有另一种方法可以修改在文件资源管理器打开时不会引发错误的时间戳?我应该自动关闭File Explorer吗?或者,如果我的应用程序只需要失败,那么我想在任何文件操作发生之前失败。有没有办法提前确定Directory.SetCreationTimeUtc()是否会遇到IOException

提前致谢。

编辑:我发现了一个。以下是您可以用来尝试重新创建问题的示例代码:

using System;
using System.IO;

namespace CreationTimeTest
{
    class Program
    {
        static void Main( string[] args )
        {
            try
            {
                DirectoryInfo di = new DirectoryInfo( @"C:\Test" );

                di.CreationTimeUtc = DateTime.UtcNow;

                Console.WriteLine( di.FullName + " creation time set to " + di.CreationTimeUtc );
            }
            catch ( Exception ex )
            {
                Console.WriteLine( ex );
                //throw;
            }

            finally
            {
                Console.ReadKey( true );
            }

        }
    }
}

创建C:\Test,构建CreationTimeTest.exe并运行它。

我发现“另一个进程使用”错误并不总是因为文件资源管理器已打开而发生。如果C:\Test已展开,则会显示C:\文件夹。这意味着如果文件资源管理器处于打开状态且C:\从未展开,则可以设置时间戳。但是,一旦C:\Test在文件资源管理器中可见,它似乎记住该文件夹,即使在C:\折叠后也不允许修改任何时间戳。任何人都可以重新创建吗?

编辑:我现在认为这是文件资源管理器错误。

我在多个Windows 10设备上使用CreationTimeTest重新创建了此行为。尝试设置创建时间有两种方法可以抛出“由另一个进程使用”异常。第一种是在主窗格中打开C:\Test,但在这种情况下,您可以离开C:\Test,然后程序将再次成功运行。但第二种方法是在导航窗格中显示C:\Test,即展开C:\。一旦你完成了这一点,似乎文件资源管理器会保持句柄处于打开状态,因为即使你关闭文件资源管理器直到崩溃C:\,程序仍然会失败。

我之前错了。让C:\Test可见不会导致问题。可以在主窗格中看到C:\Test而不会出现问题。它在导航窗格中的可见性才是最重要的。

2 个答案:

答案 0 :(得分:1)

试试这个:

        string sourcePath = "";
        string targetPath = "";

        DirectoryInfo sourceDirectoryInfo = new DirectoryInfo(sourcePath);

        FileSystem.CopyDirectory(sourcePath, targetPath, overwrite);

        DirectoryInfo targetDirectory = new DirectoryInfo(targetPath);

        targetDirectory.CreationTimeUtc = sourceDirectoryInfo.CreationTimeUtc;
        targetDirectory.LastAccessTimeUtc = sourceDirectoryInfo.LastAccessTimeUtc;
        targetDirectory.LastWriteTimeUtc = sourceDirectoryInfo.LastWriteTimeUtc;

        Directory.Delete(sourcePath, true);

这将允许您设置目标目录的创建/访问/写入时间,只要目录本身没有在资源管理器中打开(我假设它不会,因为它只是刚刚创建)。

答案 1 :(得分:1)

我怀疑FileSystem.CopyDirectory与资源管理器的联系,并以某种方式阻止该目录。尝试使用标准C#方法复制所有文件和目录,如下所示:

DirectoryCopy(@"C:\SourceDirectory", @"D:\DestinationDirectory", true);

使用这些实用程序方法:

private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
    // Get the subdirectories for the specified directory.
    DirectoryInfo dir = new DirectoryInfo(sourceDirName);

    if (!dir.Exists)
    {
        throw new DirectoryNotFoundException("Source directory does not exist or could not be found: " + sourceDirName);
    }

    if ((dir.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
    {
        // Don't copy symbolic links
        return;
    }

    var createdDirectory = false;
    // If the destination directory doesn't exist, create it.
    if (!Directory.Exists(destDirName))
    {
        var newdir = Directory.CreateDirectory(destDirName);
        createdDirectory = true;
    }

    // Get the files in the directory and copy them to the new location.
    DirectoryInfo[] dirs = dir.GetDirectories();
    FileInfo[] files = dir.GetFiles();
    foreach (FileInfo file in files)
    {
        if ((file.Attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint)
            continue; // Don't copy symbolic links

        string temppath = Path.Combine(destDirName, file.Name);
        file.CopyTo(temppath, false);
        CopyMetaData(file, new FileInfo(temppath));
    }

    // If copying subdirectories, copy them and their contents to new location.
    if (copySubDirs)
    {
        foreach (DirectoryInfo subdir in dirs)
        {
            string temppath = Path.Combine(destDirName, subdir.Name);
            DirectoryCopy(subdir.FullName, temppath, copySubDirs);
        }
    }

    if (createdDirectory)
    {
        // We must set it AFTER copying all files in the directory - otherwise the timestamp gets updated to Now.
        CopyMetaData(dir, new DirectoryInfo(destDirName));
    }
}

private static void CopyMetaData(FileSystemInfo source, FileSystemInfo dest)
{
    dest.Attributes = source.Attributes;
    dest.CreationTimeUtc = source.CreationTimeUtc;
    dest.LastAccessTimeUtc = source.LastAccessTimeUtc;
    dest.LastWriteTimeUtc = source.LastWriteTimeUtc;
}