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
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.
If you need to access a UNC path or admin share using different credentials: MSDN
To bootstrap use of WNetAddConnection2 use this code:
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);
}
}
So i went with the
bool success = File.Exists(path + Filename);
option, as opposed to using the FileInfo route.
Thanks for all the suggestions!
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.
See this question:
how can you easily check if access is denied for a file in .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.
I suspect the reason the UNC path fails is either 1) a permissions issue accessing the admin share from the user running your app, or 2) 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.
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: very expensive. 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:
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:
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.
And that's only the beginning of the story. When you use .Exists()
, you incur this additional cost (and it is an addition: you have to do the same work again when you go to open the file) on every attempt. 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.
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.
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 fi = new FileInfo(somePath);
bool exists = fi.Exists;
Update: In a short test this also worked for UNC paths, e.g. like this:
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$".
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);
vs:
success = File.Exists(Path.Join(path,pattern));