2009-01-19 37 views
22

Tôi đang cố gắng viết một hàm để xác định xem tệp có tồn tại hay không. Hai phương thức chứng minh trả về các kết quả không nhất quán (fileExists() dường như cung cấp kết quả chính xác, so với isFileFound(), trả về các kết quả dương tính giả - tôi có thể mong đợi một ngoại lệ khi cố gắng tạo cá thể).Xác định xem tệp có tồn tại hay không bằng cách sử dụng C# và giải quyết đường dẫn UNC

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; 
    } 

Không có vẻ để có thể giải quyết một đường dẫn UNC của cú pháp sau: \\ abcserver \ c $ \ xyzfolder \ foo.bar

Bất cứ ý tưởng tại sao các đường dẫn UNC là thất bại cho những phương pháp này sẽ được đánh giá cao.

+14

FYI - Là một bác sĩ đa khoa, tôi cố gắng sử dụng System.IO.Path.Combine (đường dẫn, tên tệp) thay vì chuỗi nối: đường dẫn + tên tệp – Ryan

+3

Thông báo trước: IO.Path.Combine ("D: \ Files", "\ foo.xml") sẽ cung cấp cho bạn "\ foo .xml "và điều tiếp theo bạn biết là bạn đã lưu các tệp vào thư mục gốc. – Tyler

Trả lời

32

Bạn có thể tạo một FileInfo cho một tệp không tồn tại. Nhưng sau đó bạn có thể kiểm tra FileInfo.Exists tài sản để xác định xem các tập tin tồn tại, ví dụ:

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

Cập nhật: Trong một bài kiểm tra ngắn này cũng làm việc cho đường dẫn UNC, ví dụ như thế này:

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

Bạn có chắc chắn rằng tài khoản (mà ứng dụng của bạn đang chạy) có quyền truy cập vào phần chia sẻ. Tôi nghĩ rằng (theo mặc định) quyền quản trị được yêu cầu để truy cập vào phần "c $".

+0

Ok, nhưng đường dẫn UNC thì sao? Ngay cả với việc sửa đổi phương thức này, không phương thức nào có thể giải quyết định dạng đường dẫn UNC trong câu hỏi ban đầu của tôi. –

+0

Đã thử một thư mục thay thế có chia sẻ $ d và thư mục đó hoạt động. Một ít đào kết luận rằng đường dẫn UNC là hợp lệ, nhưng một số thay đổi quyền là cần thiết. –

+1

Làm thế nào tăng tốc độ File.Exists cho các cổ phiếu mạng không tồn tại? – Kiquenet

11

Xem câu hỏi này:
how can you easily check if access is denied for a file in .NET?

Các phiên bản ngắn của câu hỏi đó là bạn không, bởi vì hệ thống tập tin là không ổn định. Chỉ cần cố gắng để mở tập tin và bắt ngoại lệ nếu nó không thành công.

Lý do phương pháp isFileFound của bạn không hoạt động do cấu trúc FileInfo bạn đang sử dụng cũng có thể được sử dụng để tạo tệp. Bạn có thể tạo một đối tượng FileInfo với thông tin mong muốn cho một tệp không tồn tại, gọi nó là phương thức .Create() và bạn đã đặt tất cả các thuộc tính mong muốn cùng một lúc.

tôi nghi ngờ lý do đường dẫn UNC thất bại hoặc là 1) sự cố cấp quyền truy cập vào phần quản trị từ người dùng chạy ứng dụng của bạn, hoặc 2) Biểu tượng $ được ném phương pháp tắt, hoặc là bởi vì nó không phải là đầu vào một cách chính xác hoặc vì một lỗi trong phần thực thi .Exists() cơ bản.

Cập nhật:

Khi tôi gửi đề nghị này, tôi gần như luôn luôn có được một lời phàn nàn về hiệu suất ngoại lệ. Hãy nói về điều đó. Có, xử lý ngoại lệ rất tốn kém: rất đắt tiền. Có vài điều bạn có thể làm trong lập trình chậm hơn. Nhưng bạn biết những gì một vài điều là? Đĩa và mạng I/O.Dưới đây là một liên kết mà chứng tỏ chỉ có bao nhiêu đĩa I/O và mạng I/O chi phí:

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

Nếu suy nghĩ trong nano giây không phải là điều bạn, đây là một liên kết bình thường hóa một chu kỳ CPU như 1 giây và quy mô từ đó:

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

Lấy ngay cả trường hợp tốt nhất cho trường hợp ngoại lệ, bạn có thể truy cập bộ nhớ ít nhất 480 lần trong khi chờ phản hồi đầu tiên từ đĩa và giả định SSD rất nhanh. Nhiều người trong chúng ta vẫn cần quay đĩa cứng, nơi mọi thứ trở nên tồi tệ hơn nhiều.

Và đó mới chỉ là khởi đầu của câu chuyện. Khi bạn sử dụng .Exists(), bạn phải chịu thêm chi phí bổ sung (và đó là một bổ sung: bạn phải thực hiện lại công việc đó một lần nữa khi bạn mở tệp) trên mỗi lần thử. Bạn trả chi phí này cho dù tệp tồn tại hay không, vì đĩa vẫn phải tìm kiếm nó trong các bảng tệp của nó. Với phương pháp ngoại lệ, bạn chỉ phải trả thêm chi phí cho việc mở ngăn xếp cuộc gọi trong trường hợp thất bại.

Nói cách khác, có: trường hợp ngoại lệ rất tốn kém. Nhưng so với việc kiểm tra đĩa, nó vẫn còn nhanh hơn: và không chỉ bằng một lề nhỏ. Rất may, điều này không có khả năng thúc đẩy hiệu suất chung của ứng dụng của bạn ... nhưng tôi vẫn muốn đưa ra lý lẽ "ngoại lệ chậm" cho tác vụ cụ thể này.

+2

Hãy coi chừng rằng việc đánh bắt các ngoại lệ có thể rất tốn kém. Nếu bạn định thực hiện các thao tác tệp hàng loạt, bạn sẽ tốt hơn nhiều trong việc kiểm tra sự tồn tại của tệp * và * bắt ngoại lệ. –

+1

@IfeanyiEcheruo So với chi phí hoạt động của tệp mạng và chi phí của các lỗi cửa sổ thời gian douboemprocessinand có thể xảy ra, chi phí bắt ngoại lệ hoàn toàn không đáng kể. – EJP

+1

Đặt một cách khác: với kiểm tra '.Exists()', bạn _always_ trả chi phí mạng và đĩa i/o để khám phá điều này, cho dù tệp có tồn tại hay không. Với phương pháp ngoại lệ, bạn chỉ phải trả thêm chi phí cho việc mở ngăn xếp cuộc gọi trong trường hợp thất bại. Ngoài ra, đắt tiền như trường hợp ngoại lệ, mạng và đĩa i/o là nhiều, _much_ tồi tệ hơn. Trong thực tế, tôi nghĩ rằng tôi sẽ thêm điều này vào câu trả lời. –

3

Điều này có thể xảy ra hoặc có thể không xảy ra, nhưng bạn có thể tham gia đường dẫn tên tệp không chính xác cho một trong các trường hợp của bạn hay không.

Điều này:

success = File.Exists (path + pattern);

so với:

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

+0

Tôi nghĩ rằng bạn có nghĩa là ['Path.Combine'] (https://msdn.microsoft.com/en-us/library/fyy7a5kt.aspx), không phải là' Path.Join'. –

1

này có thể giúp bạn:
http://www.codeplex.com/FileDirectoryPath
Đó là NDepend.Helpers.FilePathDirectory, rằng có một "tính hợp lệ Đường dẫn kiểm tra API" trong số khác có thể hữu ích.

1

Vì vậy, tôi đã đi với các tùy chọn

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

, như trái ngược với việc sử dụng các tuyến đường FileInfo.

Cảm ơn tất cả các đề xuất!

+6

Bạn có thể muốn sử dụng System.IO.Path.Combine (đường dẫn, tên tệp) thay vì thêm chuỗi. Điều này sẽ giải quyết các trường hợp góc, ví dụ: "a \" + "b" = "a \ b" và Path.Combine ("a \", "b") = "a \ b" nhưng "a" + "b" = "ab" và Path.Combine ("a", "b") = "a \ b" –

1

Chỉnh sửa: Tôi vừa nhận ra tệp .exists hoạt động ok. Đó chắc chắn sẽ là phương pháp ưa thích. Dưới đây mã sẽ cung cấp cho bạn tùy chọn có cửa sổ nhắc người dùng xác thực, nếu chia sẻ nên được truy cập theo một tài khoản tên miền khác nhau. Có thể giúp ai đó một ngày nào đó vì vậy tôi sẽ để lại mã ở đây.

Nếu bạn cần truy cập vào một đường dẫn hoặc quản trị UNC phần bằng các thông tin khác nhau: MSDN

Để bootstrap sử dụng WNetAddConnection2 sử dụng mã này:

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); 

    } 
} 
Các vấn đề liên quan