2011-02-03 9 views
10

संभव डुप्लिकेट बात:
Best way to determine if two path reference to same file in C#मैं कैसे तय कर सकते हैं कि कई फ़ाइल पथ प्रारूपों समान भौतिक स्थान को

एक निर्देशिका स्थान निर्दिष्ट करने के कई तरीके हैं।

उदाहरण के लिए:
\\ machineName \ ग $ \ rootPath \ सब-पाथ
\\ machineName \ Sharename (शेयर सब-पाथ को इशारा)
C: \ rootPath \ सब-पाथ
सब-पाथ (सापेक्ष पथ अगर सी में पहले से ही: \ rootPath +०१२३५०९५२९

मुझे यह निर्धारित करने की आवश्यकता है कि ये सभी पथ एक दूसरे के बराबर "बराबर" हैं (वास्तव में हार्ड ड्राइव पर एक ही भौतिक स्थान हैं)।

क्या कोई तरीका है कि मैं इसे सी # में कर सकता हूं?

+1

, आप 'System.IO.Path.GetFullPath' – Jimmy

उत्तर

5

ओडेड राज्यों में यह करना मुश्किल है। नेट। आप संभवतया स्थान पर एक लंबे समय से जेनरेट किए गए फ़ाइल नाम के साथ फ़ाइल लिखकर धोखा दे सकते हैं (अपनी सटीक आवश्यकताओं और अनुमतियों आदि को छोड़कर) और फिर देख सकते हैं कि आप इसे दूसरे स्थान से देख सकते हैं या नहीं। एक हैक का बिट, लेकिन यह एक सुंदर ध्वनि परीक्षण है जो मुझे लगता है कि मैप किए गए ड्राइव आदि को हल करने के बजाय,

ठीक है वीबी के लिए कई माफ़ी - यह सब मुझे इस छोटी नेटबुक पर मिला है ... सी # होगा 'टी भी अलग हो ...

उपयोग जैसे

If sameLocation("\\machineName\c$\rootPath\subPath","\\machineName\shareName") Then...

Public Function sameLocation(ByVal sPath1 As String, ByVal sPath2 As String) As TriState 
    Dim sFile As String = randomFilename() 
    Dim sFullPath1 As String = sPath1 & "\" & sFile 
    Dim sFullPath2 As String = sPath2 & "\" & sFile 
    Dim bReturn As Boolean = False 
    Try 
     Dim fs As New FileStream(sFullPath1, FileMode.CreateNew) 
     fs.Close() 
    Catch ex As Exception 
     Return TriState.UseDefault 
    End Try 

    Try 
     bReturn = File.Exists(sFullPath2) 
    Catch ex As Exception 
     Return TriState.UseDefault 
    End Try 

    File.Delete(sFullPath1) 
    Return bReturn 
End Function 

Public Function randomFilename() As String 
    Dim r As New Random 
    Randomize(My.Computer.Clock.TickCount) 
    Dim sb As New StringBuilder 
    Dim chars As Int16 = 100 
    While chars > 0 
     chars -= 1 
     sb.Append(Chr(r.Next(26) + 65)) 
    End While 
    Return sb.ToString 
End Function 

आप और अधिक सुरक्षा, यानी पढ़ने टाइमस्टैम्प आदि जोड़ सकते हैं ...

+1

शायद आपको सबसे अच्छा जवाब मिलेगा, यदि आपका प्रोग्राम और चल रहे उपयोगकर्ता को उन फ़ोल्डरों को पढ़ने/लिखने का अधिकार है। – KeithS

+0

यदि फ़ाइल नाम स्वयं एक उपनाम है तो आप इस तरह से कभी नहीं जान पाएंगे। केवल अगर अलियासिंग पथ में कहीं है। –

+0

कृपया नीचे जाने पर टिप्पणियां छोड़ें !!! –

0

.NET में ऐसा करने का कोई मूल तरीका नहीं है - यह बहुत कम स्तर है।

आप इसे प्राप्त करने के लिए विंडोज एपीआई का उपयोग करने में सक्षम हो सकते हैं (निर्देशिका इनोड या कुछ अन्य पहचानकर्ता को देख रहे हैं), लेकिन मुझे नहीं पता कि एपीआई इसका खुलासा करेगी।

+1

AFAIK का उपयोग कर सकते हैं Windows में कोई इनोड नहीं हैं। –

+0

@ एएल - मुझे वास्तव में पता नहीं है कि क्या हैं या नहीं, इसलिए मैंने "या कुछ अन्य पहचानकर्ता" कहा था। – Oded

+0

एफएटी, एक के लिए, इसके नाम को छोड़कर एक अद्वितीय फ़ाइल पहचानकर्ता नहीं है। और कौन जानता है कि किस तरह के अजीब फाइल सिस्टम नेटवर्क के माध्यम से उपलब्ध हो सकते हैं। –

0

AKAIK आप कई ड्राइव अक्षरों या उपनिर्देशिकाओं के लिए एक ही ड्राइव को मानचित्र भी बना सकते हैं। नेटवर्क साझा निर्देशिकाओं को भी गुणा किया जा सकता है और आप कभी नहीं जानते कि वे समान हैं या नहीं।

शायद आप जानकारी जोड़ सकते हैं क्यों आपको इसे जानने की आवश्यकता है।

4

आपको GetFileInformationByHandle का उपयोग करने की आवश्यकता है।
स्टैक ओवरव्लो और MSDN सहायता में यह answer देखें।

using System; 
using System.Runtime.InteropServices; 

namespace CompareByPath  
{  
    public static class DirectoryHelper 
    { 
    // all user defined types copied from 
    // http://pinvoke.net/default.aspx/kernel32.CreateFile 
    // http://pinvoke.net/default.aspx/kernel32.GetFileInformationByHandle 
    // http://pinvoke.net/default.aspx/kernel32.CloseHandle 

    public const short INVALID_HANDLE_VALUE = -1; 

    struct BY_HANDLE_FILE_INFORMATION 
    { 
     public uint FileAttributes; 
     public System.Runtime.InteropServices.ComTypes.FILETIME CreationTime; 
     public System.Runtime.InteropServices.ComTypes.FILETIME LastAccessTime; 
     public System.Runtime.InteropServices.ComTypes.FILETIME LastWriteTime; 
     public uint VolumeSerialNumber; 
     public uint FileSizeHigh; 
     public uint FileSizeLow; 
     public uint NumberOfLinks; 
     public uint FileIndexHigh; 
     public uint FileIndexLow; 
    } 

    [Flags] 
    public enum EFileAccess : uint 
    { 
     GenericRead = 0x80000000, 
     GenericWrite = 0x40000000, 
     GenericExecute = 0x20000000, 
     GenericAll = 0x10000000 
    } 

    [Flags] 
    public enum EFileShare : uint 
    { 
     None = 0x00000000, 
     Read = 0x00000001, 
     Write = 0x00000002, 
     Delete = 0x00000004 
    } 

    [Flags] 
    public enum EFileAttributes : uint 
    { 
     Readonly = 0x00000001, 
     Hidden = 0x00000002, 
     System = 0x00000004, 
     Directory = 0x00000010, 
     Archive = 0x00000020, 
     Device = 0x00000040, 
     Normal = 0x00000080, 
     Temporary = 0x00000100, 
     SparseFile = 0x00000200, 
     ReparsePoint = 0x00000400, 
     Compressed = 0x00000800, 
     Offline = 0x00001000, 
     NotContentIndexed = 0x00002000, 
     Encrypted = 0x00004000, 
     Write_Through = 0x80000000, 
     Overlapped = 0x40000000, 
     NoBuffering = 0x20000000, 
     RandomAccess = 0x10000000, 
     SequentialScan = 0x08000000, 
     DeleteOnClose = 0x04000000, 
     BackupSemantics = 0x02000000, 
     PosixSemantics = 0x01000000, 
     OpenReparsePoint = 0x00200000, 
     OpenNoRecall = 0x00100000, 
     FirstPipeInstance = 0x00080000 
    } 

    public enum ECreationDisposition : uint 
    { 
     New = 1, 
     CreateAlways = 2, 
     OpenExisting = 3, 
     OpenAlways = 4, 
     TruncateExisting = 5 
    } 

    [DllImport("kernel32.dll", SetLastError = true)] 
    static extern bool GetFileInformationByHandle(IntPtr hFile, out  BY_HANDLE_FILE_INFORMATION lpFileInformation); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)] 
    static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile); 

    [DllImport("kernel32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    static extern bool CloseHandle(IntPtr hObject); 

    public static bool CompareDirectories(string d1, string d2) 
    { 
     bool result = false; 

     BY_HANDLE_FILE_INFORMATION info1; 
     BY_HANDLE_FILE_INFORMATION info2; 

     IntPtr fileHandle1 = CreateFile(d1, (uint)EFileAccess.GenericRead, (uint)EFileShare.Read, IntPtr.Zero, (uint)ECreationDisposition.OpenExisting, (uint)(EFileAttributes.Directory | EFileAttributes.BackupSemantics), IntPtr.Zero); 
     if (fileHandle1.ToInt32() != INVALID_HANDLE_VALUE) 
     { 
     bool rc = GetFileInformationByHandle(fileHandle1, out info1); 
     if (rc) 
     { 
      IntPtr fileHandle2 = CreateFile(d2, (uint)EFileAccess.GenericRead, (uint)EFileShare.Read, IntPtr.Zero, (uint)ECreationDisposition.OpenExisting, (uint)(EFileAttributes.Directory | EFileAttributes.BackupSemantics), IntPtr.Zero); 
      if (fileHandle2.ToInt32() != INVALID_HANDLE_VALUE) 
      { 
      rc = GetFileInformationByHandle(fileHandle2, out info2); 
      if (rc) 
      { 
       if ((info1.FileIndexHigh == info2.FileIndexHigh) && 
        (info1.FileIndexLow == info2.FileIndexLow) && 
        (info1.VolumeSerialNumber == info2.VolumeSerialNumber)) 
       { 
       result = true; 
       } 
      } 
      } 

      CloseHandle(fileHandle2); 
     } 
     } 

     CloseHandle(fileHandle1); 

     return result; 
    } 
    } 
} 
0

अच्छा सवाल है, वहाँ एक सुंदर जवाब नहीं हो सकता है:

यहाँ एक विधि मैं ने लिखा है कि निर्देशिका के साथ काम करता है।

सबसे अच्छा मैं आपको अपने रास्ते पर इंगित करने के लिए पा सकता हूं net share कमांड लाइन स्टेटमेंट है। यदि आप प्रोग्राम द्वारा इस आदेश द्वारा उत्पादित पाठ को कैप्चर और पच सकते हैं, तो आप अपने स्थानीय गंतव्य फ़ोल्डर्स में नेटवर्क शेयर 1: 1 को मैप कर सकते हैं। फिर आप किसी दिए गए पथ में उन शेयर मैप्स के उदाहरणों को देख सकते हैं और बुनियादी स्ट्रिंग तुलना करने से पहले स्थानीय फ़ोल्डर समकक्षों के साथ उन्हें प्रतिस्थापित कर सकते हैं।

2

वहाँ Windows में कई अलियासिंग योजनाओं हैं:

  • कम बनाम लंबा नाम
  • सिमलिंक और
  • यूएनसी नाम hardlinks बनाम मैप की ड्राइव एक ही नेटवर्क पथ
  • करने के लिए
  • कई मैप की ड्राइव
  • घ: \ फ़ोल्डर \ पथ बनाम \ \ घ \ folder \ पथ
  • NTFS माउंट अंक

और इनमें से कोई भी निर्देशिका पेड़ में किसी भी स्तर पर दिखाई दे सकता है। .NET में, आप इनमें से कुछ को हल कर सकते हैं, लेकिन दूसरों को नहीं।

इसके आस-पास एक हैकिश तरीका के रूप में, लॉकिंग/अनलॉक करने का प्रयास करें। फ़ाइल को नाम 1 के रूप में लॉक करें, नाम 2 के रूप में खोलने का प्रयास करें, सुनिश्चित करें कि यह विफल हो जाता है। फिर अनलॉक करें, फिर से खोलने का प्रयास करें, सुनिश्चित करें कि यह सफल हो गया है। और आगे, झूठी सकारात्मक से बचने के लिए कुछ बार। एल रोनाको के रास्ते के विपरीत, यह पथ-स्तर और फ़ाइल-स्तरीय एलियासिंग दोनों का पता लगाता है।

कुछ नेटवर्क फाइल सिस्टम पर, लॉकिंग बिल्कुल समर्थित नहीं हो सकता है। इसके अलावा, इसमें कुछ समय लग सकता है - प्रत्येक लॉक/अनलॉक/ओपन ऑपरेशन एक नेटवर्क राउंडट्रिप है।

लेकिन यह वास्तव में आपकी आवश्यकताओं पर निर्भर करता है। यदि छोटे/लंबे नामों को आप सभी के साथ सौदा करना है, तो यह एक ओवरकिल है।

संपादित करें: फ़ाइल केवल पढ़ने के लिए अतिरिक्त जटिलताओं या केवल किसी और द्वारा खुली है। सापेक्ष पथों को हल करने के लिए

+0

+1 मुझे उत्तर पसंद है लेकिन मुझे यकीन नहीं है कि मौजूदा सामग्री को नष्ट करने के तरीके के बारे में मेरा क्या मतलब है? मेरी विधि में एक खाली फ़ाइल बनाना शामिल होगा। –

+0

@ एलएल रोनोको: गलत समझा, क्षमा करें। आपका तरीका फ़ाइल नाम-स्तर एलियासिंग का पता नहीं लगाता है, हालांकि। –

+0

@ सेव यह ठीक है, मुझे यह भी नहीं पता कि वह क्या है! :) –

संबंधित मुद्दे