首页 > 解决方案 > 如何指定 createfilew 函数获取未缓存的结果?

问题描述

我需要检查一个文件(在远程服务器上通过UNC path)是否存在(权限在这里不是问题;我进行了必需的模拟等)。

我使用CreateFileW函数来创建file handle. 我也试过GetFileAttributesEx但行为是一样的。

HANDLE CreateFileW(
  LPCWSTR               lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);

如果我处理UNC paths我可能会因为UNC 缓存而得到错误的结果(不同的进程复制或删除我需要检查的文件)。它取决于FileNotFoundCacheLifetime注册表项值(默认值为 10 秒)。

// lets say I would like to check a file
// in the beginning the file exists
// than another process delete this file
// (e.g. executing drop database command by sql server)
// than another process copies this file back
// and all steps above takes less then FileNotFoundCacheLifetime value

// path = @"\\server\C$\Tmp\Folder\database\myDb.mdf"
private static void Test(string path)
{
    File.Exists(path);                              //exists
    Directory.Exists(Path.GetDirectoryName(path));  //exists

    using (var handle = CreateFile(path, EFileAccess.GenericRead, EFileShare.Read, IntPtr.Zero,
        ECreationDisposition.OpenExisting, EFileAttributes.Normal, IntPtr.Zero))
    {
        if (handle == null || handle.IsInvalid)
        {
            //FileNotFoundCacheLifetime = 0  => exists
            //FileNotFoundCacheLifetime = 10 => Win32Exception - The system cannot find the file specified
            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        }
    }
}

[DllImport("kernel32.dll", EntryPoint = "CreateFileW", ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
public static extern SafeFileHandle CreateFile(
    string lpFileName,
    EFileAccess dwDesiredAccess,
    EFileShare dwShareMode,
    IntPtr lpSecurityAttributes,
    ECreationDisposition dwCreationDisposition,
    EFileAttributes dwFlagsAndAttributes,
    IntPtr hTemplateFile);

#region CreateFile
[Flags]
public enum EFileAccess : uint
{
    GenericRead = 0x80000000,
    GenericWrite = 0x40000000,
    GenericExecute = 0x20000000,
    GenericAll = 0x10000000,
}

[Flags]
public enum EFileShare : uint
{
    None = 0x00000000,
    Read = 0x00000001,
    Write = 0x00000002,
    Delete = 0x00000004,
}

public enum ECreationDisposition : uint
{
    New = 1,
    CreateAlways = 2,
    OpenExisting = 3,
    OpenAlways = 4,
    TruncateExisting = 5,
}

[Flags]
public enum EFileAttributes : uint
{
    Readonly = 0x00000001,
    Hidden = 0x00000002,
    System = 0x00000004,
    Directory = 0x00000010,
    Archive = 0x00000020,
    Device = 0x00000040,
    Normal = 0x00000080,
    Temporary = 0x00000100,
    SparseFile = 0x00000200,
    ReparsePoint = 0x00000400,
    Compressed = 0x00000800,
    Offline = 0x00001000,
    NotContentIndexed = 0x00002000,
    Encrypted = 0x00004000,
    Write_Through = 0x80000000,
    Overlapped = 0x40000000,
    NoBuffering = 0x20000000,
    RandomAccess = 0x10000000,
    SequentialScan = 0x08000000,
    DeleteOnClose = 0x04000000,
    BackupSemantics = 0x02000000,
    PosixSemantics = 0x01000000,
    OpenReparsePoint = 0x00200000,
    OpenNoRecall = 0x00100000,
    FirstPipeInstance = 0x00080000
}
#endregion CreateFile

你知道如何获得未缓存的结果吗?基本上我可以禁用UNC cache我知道的。在这里,我需要一种不同的方法——如何精确地为特定的方法调用获取未缓存的结果。

我知道以下方法 - $NOCSC$( @"\\server$NOCSC$\C$\folder\file") 修饰符,但不幸的是它不适用于所有操作系统。

File.Exists()并且Folder.Exists()有效,但我需要fileapi,因为它支持长路径(基本上它只是一个可行的解决方案)。

另一个对我来说很好的解决方案是以编程方式清理 UNC 文件系统缓存(同样在特定方法调用之前)。

标签: c#c++.netfilesystems

解决方案


在博客 mdsn上有一个针对长路径的修复(根据您对这篇文章的评论),它是 .net 4.6.2 及更高版本的申请人。

您必须将应用程序清单文件项添加到您的项目中,博客中有详细的流程指南,但总而言之,这似乎是解决您的问题的好方法,没有任何不必要的麻烦。

在示例中,他们确实在控制台应用程序上对其进行了测试,因此您必须弄清楚如何对您的解决方案进行适当的调整。


推荐阅读