我正在尝试编写一个函数来确定文件是否存在。这两种方法证明返回不一致的结果(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;
}
似乎无法解析以下语法的UNC路径: \\ abcserver \ c $ \ xyzfolder \ foo.bar
任何想法为什么这些方法的unc路径失败都将非常感激。
答案 0 :(得分:37)
您可以为不存在的文件创建FileInfo。但是,您可以检查FileInfo.Exists属性以确定该文件是否存在,例如:
FileInfo fi = new FileInfo(somePath);
bool exists = fi.Exists;
<强>更新强>: 在一个简短的测试中,这也适用于UNC路径,例如像这样:
FileInfo fi = new FileInfo(@"\\server\share\file.txt");
bool exists = fi.Exists;
您确定该帐户(运行您的应用程序)可以访问该共享。我认为(默认情况下)管理权限是访问共享“c $”所必需的。
答案 1 :(得分:13)
看到这个问题:
how can you easily check if access is denied for a file in .NET?
该问题的简短版本是您没有,因为文件系统是易变的。只是尝试打开文件并在失败时捕获异常。
isFileFound
方法不起作用的原因是因为您使用的FileInfo
结构也可用于创建文件。您可以使用所需信息创建一个FileInfo对象,调用它的.Create()
方法,然后一次性设置所需的属性。
我怀疑UNC路径失败的原因是1)从运行您的应用的用户访问管理员共享的权限问题,或 2)$
符号抛出方法off,要么是因为它没有正确输入,要么是因为底层.Exists()实现中的错误。
更新:
当我发布此建议时,我几乎总是会收到关于异常性能的投诉。我们来谈谈这个。是的,处理异常非常昂贵:非常昂贵。在编程中你可以做的事情很少。但是你知道那些东西是什么吗?磁盘和网络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
如果在纳秒内思考不是你的事,那么这是另一个将一个CPU周期标准化为1秒并从那里扩展的链接:
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
即使是异常的最佳情况,您也可以在等待来自磁盘的第一个响应时访问内存至少480次,而且假设SSD速度非常快。我们中的许多人仍然需要旋转硬盘,事情变得更糟,更糟糕。
这只是故事的开头。当您使用.Exists()
时,会产生额外的费用(这是一个额外的内容:您必须在打开文件时再次执行相同的工作)每个< / em>尝试。无论文件是否存在,您都要支付这笔费用,因为磁盘仍然需要在文件表中查找。使用异常方法,您只需支付在失败的情况下展开调用堆栈的额外成本。
换句话说,是的:例外情况非常昂贵。但与磁盘检查相比,它仍然更快:而不仅仅是一小部分。值得庆幸的是,这不太可能推动您的应用程序的一般性能...但我仍然想要为这项特定任务上台“异常缓慢”的论点。
答案 2 :(得分:3)
这可能是也可能不是,但您可能会因为某个案例而错误地加入您的路径文件名。
此:
success = File.Exists(path + pattern);
VS
success = File.Exists(Path.Join(path,pattern));
答案 3 :(得分:1)
这可以帮到你:
http://www.codeplex.com/FileDirectoryPath
它是 NDepend.Helpers.FilePathDirectory ,其中包含一个“路径有效性检查API”,可能很有用。
答案 4 :(得分:1)
所以我选择了
bool success = File.Exists(path + Filename);
选项,而不是使用FileInfo路由。
感谢所有的建议!
答案 5 :(得分:1)
编辑:我刚刚意识到file.exists正常工作。这绝对是首选的方法。如果应在不同的域帐户下访问共享,则下面的代码将为您提供让Windows提示用户进行身份验证的选项。有一天可能会帮助某人,所以我会把代码放在这里。
如果您需要使用其他凭据访问UNC路径或管理员共享:MSDN
要使用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);
}
}