使用c#确定文件是否存在并解析UNC路径

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/458363/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 04:11:41  来源:igfitidea点击:

Determining if file exists using c# and resolving UNC path

c#filesystems

提问by steve_mtl

I am trying to write a function to determine if a file exists. The two methods prove to return inconsistent results (fileExists() seems to provide accurate results, compared to isFileFound(), that returns false positives - i would have expected an exception when trying to create the instance).

我正在尝试编写一个函数来确定文件是否存在。这两种方法被证明返回不一致的结果(fileExists() 似乎提供了准确的结果,与 isFileFound() 相比,返回误报 - 我本来希望在尝试创建实例时出现异常)。

protected bool isFileFound(string path, string fileName)
    {
        System.IO.FileInfo fi = null;

        bool found = false;
        try
        {
            fi = new System.IO.FileInfo(path + fileName);
            found = true;
        }
        catch (Exception e)
        {
            baselogger.Fatal(e.Message + " " + e.StackTrace + " \n" + path + fileName);
        }

        return found;
    }

    protected bool fileExists(string path, string pattern)
    {
        bool success = false;

        try
        {
            success = File.Exists(path + pattern);
        }
        catch (Exception e)
        {
            baselogger.Warn(e.Message + " " + e.StackTrace + " " + e.Source);
        }

        return success;
    }

Neither seems to be able to resolve a UNC path of the following syntax: \\abcserver\c$\xyzfolder\foo.bar

两者似乎都无法解析以下语法的 UNC 路径:\\abcserver\c$\xyzfolder\foo.bar

Any idea why the unc path is failing for these methods would be greatly appreciated.

任何想法为什么 UNC 路径对这些方法失败的想法将不胜感激。

采纳答案by M4N

You can create a FileInfo for an non-existing file. But then you can check the FileInfo.Exists property to determine whether the file exists, e.g:

您可以为不存在的文件创建 FileInfo。但是你可以检查 FileInfo.Exists 属性来确定文件是否存在,例如:

FileInfo fi = new FileInfo(somePath);
bool exists = fi.Exists;

Update: In a short test this also worked for UNC paths, e.g. like this:

更新:在一个简短的测试中,这也适用于 UNC 路径,例如:

FileInfo fi = new FileInfo(@"\server\share\file.txt");
bool exists = fi.Exists;

Are you sure that the account (under which your application is running) has access to the share. I think that (by default) administrative rights are required to access the share "c$".

您确定该帐户(您的应用程序在其下运行)有权访问该共享。我认为(默认情况下)需要管理权限才能访问共享“c$”。

回答by Joel Coehoorn

See this question:
how can you easily check if access is denied for a file in .NET?

请参阅此问题:
如何轻松检查 .NET 中的文件是否被拒绝访问?

The short version of that question is that you don't, because the file system is volatile. Just try to open the file and catch the exception if it fails.

这个问题的简短版本是你没有,因为文件系统是不稳定的。只需尝试打开文件并在失败时捕获异常。

The reason your isFileFoundmethod doesn't work is because the FileInfostructure you are using can also be used to create files. You can create a FileInfo object with the desired info for a non-existing file, call it's .Create()method, and you've set your desired properties all at once.

您的isFileFound方法不起作用的原因是FileInfo您使用的结构也可用于创建文件。您可以为不存在的文件创建一个包含所需信息的 FileInfo 对象,调用它的.Create()方法,然后一次性设置所需的属性。

I suspect the reason the UNC path fails is either 1) a permissions issue accessing the admin share from the user running your app, or2) The $symbol is throwing the method off, either because it's not being input correctly or because of a bug in the underlying .Exists() implementation.

我怀疑 UNC 路径失败的原因是 1) 从运行您的应用程序的用户访问管理共享的权限问题,2) 该$符号正在抛出该方法,因为它没有正确输入或因为错误底层 .Exists() 实现。

Update:

更新:

When I post this suggestion, I nearly always get a complaint about exception performance. Let's talk about that. Yes, handling exceptions is expensive: veryexpensive. There are few things you can do in programming that are slower. But you know what one those few things is? Disk and network I/O. Here's a link that demonstrates just how much disk I/O and network I/O cost:

当我发布此建议时,我几乎总是收到有关异常性能的投诉。让我们来谈谈。是的,处理异常很昂贵:非常昂贵。在编程中,您可以做的事情很少是较慢的。但你知道那几件事是什么吗?磁盘和网络 I/O。这是一个演示磁盘 I/O 和网络 I/O 成本的链接:

https://gist.github.com/jboner/2841832

https://gist.github.com/jboner/2841832

Latency Comparison Numbers
--------------------------
L1 cache reference                            0.5 ns
Branch mispredict                             5   ns
L2 cache reference                            7   ns             14x L1 cache
Mutex lock/unlock                            25   ns
Main memory reference                       100   ns             20x L2 cache, 200x L1 cache
Compress 1K bytes with Zippy              3,000   ns
Send 1K bytes over 1 Gbps network        10,000   ns    0.01 ms
Read 4K randomly from SSD*              150,000   ns    0.15 ms
Read 1 MB sequentially from memory      250,000   ns    0.25 ms
Round trip within same datacenter       500,000   ns    0.5  ms
Read 1 MB sequentially from SSD*      1,000,000   ns    1    ms  4X memory
Disk seek                            10,000,000   ns   10    ms  20x datacenter roundtrip
Read 1 MB sequentially from disk     20,000,000   ns   20    ms  80x memory, 20X SSD
Send packet CA->Netherlands->CA     150,000,000   ns  150    ms

If thinking in nanoseconds isn't your thing, here's another link that normalizes one CPU cycle as 1 second and scales from there:

如果您不喜欢以纳秒为单位思考,这里有另一个链接,它将一个 CPU 周期标准化为 1 秒并从那里扩展:

http://blog.codinghorror.com/the-infinite-space-between-words/

http://blog.codinghorror.com/the-infinite-space-between-words/

1 CPU cycle             0.3 ns      1 s
Level 1 cache access    0.9 ns      3 s
Level 2 cache access    2.8 ns      9 s
Level 3 cache access    12.9 ns     43 s
Main memory access      120 ns      6 min
Solid-state disk I/O    50-150 μs   2-6 days
Rotational disk I/O     1-10 ms     1-12 months
Internet: SF to NYC     40 ms       4 years
Internet: SF to UK      81 ms       8 years
Internet: SF to AUS     183 ms      19 years
OS virt. reboot         4 s         423 years
SCSI command time-out   30 s        3000 years
Hardware virt. reboot   40 s        4000 years
Physical system reboot  5 m         32 millenia

Taking even the best-case scenario for exceptions, you can access memory at least 480 times while waiting on the first response from a disk, and that's assuming a very fast SSD. Many of us still need spinning hard-drives, where things get much, much worse.

即使是异常情况的最佳情况,在等待来自磁盘的第一个响应时,您也可以访问内存至少 480 次,并且假设 SSD 速度非常快。我们中的许多人仍然需要旋转硬盘驱动器,但情况会变得更糟。

And that's only the beginning of the story. When you use .Exists(), you incur this additionalcost (and it is an addition: you have to do the same work again when you go to open the file) on everyattempt. You pay this costs whether the file exists or not, because the disk still has to go look for it in it's file tables. With the exception method, you only pay the extra cost of unwinding the call stack in the case of failure.

而这只是故事的开始。当您使用 时.Exists()每次尝试都会产生此额外费用(这是一个额外费用:您必须在打开文件时再次执行相同的工作)。无论文件是否存在,您都需要支付此费用,因为磁盘仍然必须在其文件表中查找它。使用异常方法,您只需支付在失败的情况下展开调用堆栈的额外成本。

In other words, yes: exceptions are horribly costly. But compared to the disk check, it's still faster: and not by just a small margin. Thankfully, this is unlikely to drive your app's general performance... but I still want to put to bed the "exceptions are slow" argument for this specific task.

换句话说,是的:异常代价高昂。但是与磁盘检查相比,它仍然更快:而且不仅仅是一小部分。值得庆幸的是,这不太可能推动您的应用程序的总体性能……但我仍然想为这个特定任务提出“异常缓慢”的论点。

回答by llamaoo7

This may or may not be the case, but could you be joining your path an file name incorrectly for one of your cases.

情况可能是这样,也可能不是,但是您是否会在其中一个案例中错误地加入文件名。

This:

这个:

success = File.Exists(path + pattern);

成功 = File.Exists(路径 + 模式);

vs:

对比:

success = File.Exists(Path.Join(path,pattern));

成功 = File.Exists(Path.Join(path,pattern));

回答by Click Ok

This can help you:
http://www.codeplex.com/FileDirectoryPath
It's NDepend.Helpers.FilePathDirectory, that have a "Path validity check API" among other that can be useful.

这可以帮助您:
http://www.codeplex.com/FileDirectoryPath
这是NDepend.Helpers.FilePathDirectory,其中有一个“路径有效性检查 API”,很有用。

回答by steve_mtl

So i went with the

所以我和

bool success = File.Exists(path + Filename);

option, as opposed to using the FileInfo route.

选项,而不是使用 FileInfo 路由。

Thanks for all the suggestions!

感谢所有的建议!

回答by HAL9000

Edit:Well I just realized file.exists works ok. That would definitely be the preferred method. Below code would give you the option of having windows prompt the user for authentication, if the share should be accessed under a different domain account. Might help somebody someday so I'll just leave the code here.

编辑:嗯,我刚刚意识到 file.exists 工作正常。那绝对是首选方法。如果应该在不同的域帐户下访问共享,下面的代码将为您提供让 Windows 提示用户进行身份验证的选项。有一天可能会帮助某人,所以我会把代码留在这里。

If you need to access a UNC path or admin share using different credentials: MSDN

如果您需要使用不同的凭据访问 UNC 路径或管理员共享: MSDN

To bootstrap use of WNetAddConnection2 use this code:

要引导使用 WNetAddConnection2,请使用以下代码:

using System;
using System.Runtime.InteropServices;

namespace Win32Api
{
    public enum ResourceScope
    {
        RESOURCE_CONNECTED = 1,
        RESOURCE_GLOBALNET,
        RESOURCE_REMEMBERED,
        RESOURCE_RECENT,
        RESOURCE_CONTEXT
    };

    public enum ResourceType
    {
        RESOURCETYPE_ANY,
        RESOURCETYPE_DISK,
        RESOURCETYPE_PRINT,
        RESOURCETYPE_RESERVED = 8
    };

    [Flags]
    public enum ResourceUsage
    {
        RESOURCEUSAGE_CONNECTABLE = 0x00000001,
        RESOURCEUSAGE_CONTAINER = 0x00000002,
        RESOURCEUSAGE_NOLOCALDEVICE = 0x00000004,
        RESOURCEUSAGE_SIBLING = 0x00000008,
        RESOURCEUSAGE_ATTACHED = 0x00000010,
        RESOURCEUSAGE_ALL = (RESOURCEUSAGE_CONNECTABLE |
                             RESOURCEUSAGE_CONTAINER | RESOURCEUSAGE_ATTACHED),
    };

    public enum ResourceDisplayType
    {
        RESOURCEDISPLAYTYPE_GENERIC,
        RESOURCEDISPLAYTYPE_DOMAIN,
        RESOURCEDISPLAYTYPE_SERVER,
        RESOURCEDISPLAYTYPE_SHARE,
        RESOURCEDISPLAYTYPE_FILE,
        RESOURCEDISPLAYTYPE_GROUP,
        RESOURCEDISPLAYTYPE_NETWORK,
        RESOURCEDISPLAYTYPE_ROOT,
        RESOURCEDISPLAYTYPE_SHAREADMIN,
        RESOURCEDISPLAYTYPE_DIRECTORY,
        RESOURCEDISPLAYTYPE_TREE,
        RESOURCEDISPLAYTYPE_NDSCONTAINER
    };

    [StructLayout(LayoutKind.Sequential)]
    public class NetResource
    {
        public ResourceScope Scope;
        public ResourceType Type;
        public ResourceDisplayType DisplayType;
        public ResourceUsage Usage;
        public string LocalName;
        public string RemoteName;
        public string Comment;
        public string Provider;
    };

    [Flags]
    public enum AddConnectionOptions
    {
        CONNECT_UPDATE_PROFILE = 0x00000001,
        CONNECT_UPDATE_RECENT = 0x00000002,
        CONNECT_TEMPORARY = 0x00000004,
        CONNECT_INTERACTIVE = 0x00000008,
        CONNECT_PROMPT = 0x00000010,
        CONNECT_NEED_DRIVE = 0x00000020,
        CONNECT_REFCOUNT = 0x00000040,
        CONNECT_REDIRECT = 0x00000080,
        CONNECT_LOCALDRIVE = 0x00000100,
        CONNECT_CURRENT_MEDIA = 0x00000200,
        CONNECT_DEFERRED = 0x00000400,
        CONNECT_RESERVED = unchecked((int)0xFF000000),
        CONNECT_COMMANDLINE = 0x00000800,
        CONNECT_CMD_SAVECRED = 0x00001000,
        CONNECT_CRED_RESET = 0x00002000
    }

    public static class NativeMethods
    {
        [DllImport("mpr.dll", EntryPoint = "WNetAddConnection2")]
        public static extern int WNetAddConnection2(
            NetResource netResource, string password,
            string username, AddConnectionOptions options);

        [DllImport("mpr.dll")]
        public static extern int WNetCancelConnection2(string name, int flags,
        bool force);

    }
}