使用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
Determining if file exists using c# and resolving UNC path
提问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 isFileFound
method doesn't work is because the FileInfo
structure 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 成本的链接:
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);
}
}