أفضل طريقة لتحديد ما إذا كان اثنين من طريق الإشارة إلى نفس الملف في C#

StackOverflow https://stackoverflow.com/questions/410705

  •  03-07-2019
  •  | 
  •  

سؤال

في القادم Java7 هناك API جديدة للتحقق مما إذا كان اثنين كائن الملف نفس الملف المرجعي.

هل هناك مماثلة API المقدمة في .NET framework ؟

لقد البحث أكثر من MSDN ولكن لا شيء ينير لي.

أريدها بسيطة ولكن أنا لا أريد أن والمقارنة بينها حسب اسم الملف الذي سوف يسبب مشاكل مع الثابت/وصلات رمزية و نمط مختلف من المسار.(مثلا ، \\?\C:\, C:\).

ما أنا ذاهب الى القيام به هو مجرد منع تكرار الملف يجري السحب انخفض إلى linklist.

هل كانت مفيدة؟

المحلول

وكما بقدر أستطيع أن أرى <لأ href = "http://hg.openjdk.java.net/nio/nio/jdk/file/d5e2831c01c4/src/windows/native/sun/nio/ch/FileKey. ج "يختلط =" noreferrer "> (1) <لأ href =" http://hg.openjdk.java.net/nio/nio/jdk/file/d5e2831c01c4/src/windows/classes/sun/ NIO / خ م / WindowsFileAttributes.java "يختلط =" noreferrer "> (2) <لأ href =" http://hg.openjdk.java.net/nio/nio/jdk/file/d5e2831c01c4/src/ النوافذ / فئات / الشمس / / NIO خ / WindowsPath.java "يختلط =" noreferrer "> (3) <لأ href =" http://hg.openjdk.java.net/nio/nio/jdk/ ملف / d5e2831c01c4 / SRC / حصة / فئات / جافا / NIO / ملف / FileRef.java "يختلط =" noreferrer "> (4) ، والطريقة JDK7 يفعل ذلك، هي عن طريق الاتصال <لأ href =" HTTP: //msdn.microsoft.com/en-us/library/aa364952(VS.85).aspx "يختلط =" noreferrer "> GetFileInformationByHandle على الملفات ومقارنة dwVolumeSerialNumber، nFileIndexHigh وnFileIndexLow.

ولكل MSDN:

<اقتباس فقرة>   

ويمكنك مقارنة عاد أعضاء VolumeSerialNumber وFileIndex في بنية BY_HANDLE_FILE_INFORMATION لتحديد ما إذا خريطة مسارين إلى نفس الهدف. على سبيل المثال، يمكنك المقارنة بين مسارات الملفات وتحديد ما إذا كانت الخريطة إلى نفس الدليل.

وأنا لا أعتقد أن يتم تغليف هذه الوظيفة .NET، لذلك سوف تضطر إلى استخدام <لأ href = "http://www.pinvoke.net/default.aspx/kernel32/GetFileInformationByHandle.html" يختلط = "noreferrer "> P / استدعاء .

ووقد تكون أو لا تعمل لملفات الشبكة. ووفقا لMSDN:

<اقتباس فقرة>   

واعتمادا على مكونات الشبكة الأساسية لنظام التشغيل ونوع الخادم متصلة، قد تفشل وظيفة GetFileInformationByHandle، والعودة معلومات جزئية، أو المعلومات الكاملة عن ملف معين.

اختبار سريع يوضح أنه يعمل كما هو متوقع (نفس القيم) مع ارتباط رمزي على نظام لينكس إتصال باستخدام SMB / سامبا، إلا أنه لا يمكن الكشف عن أن ملف هو نفسه عند الوصول إليها باستخدام سهم المختلفة التي تشير إلى نفس الملف (FileIndex هو نفسه، ولكن يختلف VolumeSerialNumber).

نصائح أخرى

تحرير:علما بأن @راسموس فابر يذكر GetFileInformationByHandle وظيفة في Win32 api و هذا يفعل ما تريد ، upvote له الجواب للحصول على مزيد من المعلومات.


أعتقد أنك بحاجة إلى نظام التشغيل وظيفة تعطيك المعلومات التي تريدها ، وإلا فإنه ستكون لدينا بعض السلبيات كاذبة مهما فعلت.

على سبيل المثال, هل هذه تشير إلى نفس الملف ؟

  • \server\share\path\filename.txt
  • \server\d$ emp\path\filename.txt

وأود أن تدرس مدى أهمية هو أن لا يكون لديك الملفات المكررة في القائمة الخاصة بك ، ثم مجرد القيام ببعض أفضل جهد.

وقد قلت ذلك, هناك طريقة في مسار الطبقة التي يمكن أن تفعل بعض الأعمال: مسار.GetFullPath, ، فإنه على الأقل سوف توسيع الطريق إلى أسماء طويلة ، وفقا الهيكل القائم.بعد ذلك أنت فقط مقارنة السلاسل.لن تكون مضمونة على الرغم من لا يريد التعامل مع اثنين من الروابط أعلاه في بلدي على سبيل المثال.

الجواب:ليس هناك طريقة مضمونة حيث يمكنك مقارنة سلسلة قاعدة مسارات لتحديد ما إذا كانت تشير إلى نفس الملف.

والسبب الرئيسي هو أن تبدو غير ذات صلة مسارات يمكن أن نشير إلى نفس الملف فعله نظام الملفات على جهاز الكمبيوتر (تقاطعات, وصلات رمزية ، الخ ...) .على سبيل المثال

"d: emp\foo.txt" "c:\othertemp\foo.txt"

هذه المسارات يمكن أن تشير إلى نفس الملف.هذه الحالة بوضوح يلغي أي سلسلة وظيفة مقارنة كأساس لتحديد إذا مسارين تشير إلى نفس الملف.

المستوى التالي هو مقارنة OS معلومات الملف.افتح ملف مسارين ومقارنة التعامل مع المعلومات.في ويندوز ويمكن أن يتم هذا مع GetFileInformationByHandle.لوسيان Wischik لم ممتازة بعد حول هذا الموضوع هنا.

لا يزال هناك مشكلة مع هذا النهج على الرغم من.أنها لا تعمل إلا إذا كان حساب المستخدم أداء الشيك قادرة على فتح كل الملفات للقراءة.هناك العديد من العناصر التي يمكن أن تمنع المستخدم من فتح واحد أو كلا الملفين.بما في ذلك ولكن لا تقتصر على ...

  • عدم وجود أذونات كافية إلى الملف
  • عدم وجود أذونات كافية إلى دليل في مسار الملف
  • نظام الملفات التغيير الذي يحدث بين فتح الملف الأول و الثاني مثل انقطاع الشبكة.

عندما تبدأ في النظر في كل هذه المشاكل يمكنك البدء في فهم لماذا يقوم نظام ويندوز لا توفر طريقة لتحديد ما إذا كان اثنين من مسارات هي نفسها.انها مجرد ليست سهلة/ممكن سؤال للإجابة.

وهنا هو C # تنفيذ IsSameFile باستخدام GetFileInformationByHandle:

وNativeMethods.cs

public static class NativeMethods
{
  [StructLayout(LayoutKind.Explicit)]
  public struct BY_HANDLE_FILE_INFORMATION
  {
    [FieldOffset(0)]
    public uint FileAttributes;

    [FieldOffset(4)]
    public FILETIME CreationTime;

    [FieldOffset(12)]
    public FILETIME LastAccessTime;

    [FieldOffset(20)]
    public FILETIME LastWriteTime;

    [FieldOffset(28)]
    public uint VolumeSerialNumber;

    [FieldOffset(32)]
    public uint FileSizeHigh;

    [FieldOffset(36)]
    public uint FileSizeLow;

    [FieldOffset(40)]
    public uint NumberOfLinks;

    [FieldOffset(44)]
    public uint FileIndexHigh;

    [FieldOffset(48)]
    public uint FileIndexLow;
  }

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

  [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  public static extern SafeFileHandle CreateFile([MarshalAs(UnmanagedType.LPTStr)] string filename,
    [MarshalAs(UnmanagedType.U4)] FileAccess access,
    [MarshalAs(UnmanagedType.U4)] FileShare share,
    IntPtr securityAttributes,
    [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
    [MarshalAs(UnmanagedType.U4)] FileAttributes flagsAndAttributes,
    IntPtr templateFile);
}

وPathUtility.cs

public static bool IsSameFile(string path1, string path2)
{
  using (SafeFileHandle sfh1 = NativeMethods.CreateFile(path1, FileAccess.Read, FileShare.ReadWrite, 
      IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
  {
    if (sfh1.IsInvalid)
      Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

    using (SafeFileHandle sfh2 = NativeMethods.CreateFile(path2, FileAccess.Read, FileShare.ReadWrite,
      IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
    {
      if (sfh2.IsInvalid)
        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

      NativeMethods.BY_HANDLE_FILE_INFORMATION fileInfo1;
      bool result1 = NativeMethods.GetFileInformationByHandle(sfh1, out fileInfo1);
      if (!result1)
        throw new IOException(string.Format("GetFileInformationByHandle has failed on {0}", path1));

      NativeMethods.BY_HANDLE_FILE_INFORMATION fileInfo2;
      bool result2 = NativeMethods.GetFileInformationByHandle(sfh2, out fileInfo2);
      if (!result2)
        throw new IOException(string.Format("GetFileInformationByHandle has failed on {0}", path2));

      return fileInfo1.VolumeSerialNumber == fileInfo2.VolumeSerialNumber
        && fileInfo1.FileIndexHigh == fileInfo2.FileIndexHigh
        && fileInfo1.FileIndexLow == fileInfo2.FileIndexLow;
    }
  }
}

البداية اعتقدت انه من السهل حقا ولكن هذا لا العمل:

  string fileName1 = @"c:\vobp.log";
  string fileName2 = @"c:\vobp.log".ToUpper();
  FileInfo fileInfo1 = new FileInfo(fileName1);
  FileInfo fileInfo2 = new FileInfo(fileName2);

  if (!fileInfo1.Exists || !fileInfo2.Exists)
  {
    throw new Exception("one of the files does not exist");
  }

  if (fileInfo1.FullName == fileInfo2.FullName)
  {
    MessageBox.Show("equal"); 
  }

ربما هذه المكتبة يساعد http://www.codeplex.com/FileDirectoryPath.أنا لم تستخدم نفسي.

تحرير: انظر هذا المثال في هذا الموقع:

  //
  // Path comparison
  //
  filePathAbsolute1 = new FilePathAbsolute(@"C:/Dir1\\File.txt");
  filePathAbsolute2 = new FilePathAbsolute(@"C:\DIR1\FILE.TXT");
  Debug.Assert(filePathAbsolute1.Equals(filePathAbsolute2));
  Debug.Assert(filePathAbsolute1 == filePathAbsolute2);

إذا كنت في حاجة إلى المقارنة نفسها أسماء مرارا وتكرارا، أود أن أقترح أن ننظر إلى canonalizing تلك الأسماء.

وبموجب نظام يونكس، هناك realpath () وظيفة التي canonalizes المسار. أعتقد أن هذا هو عادة أفضل رهان إذا كان لديك <م> معقد المسار. ومع ذلك، فمن المرجح أن تفشل على وحدات تخزين محمولة عبر اتصالات الشبكة.

ولكن، استنادا إلى نهج realpath ()، إذا كنت ترغب في دعم حجم متعددة بما في ذلك مجلدات الشبكة، يمكن أن تكتب وظيفة الخاصة بك أن يتحقق كل اسم الدليل في مسار وإذا كان يحيل الى حجم ثم تحديد ما إذا كان المرجع حجم في كلا المسارين هو نفسه. هذا يقال، وهذه النقطة جبل قد تكون مختلفة (أي مسار على حدة التخزين الوجهة قد لا تكون جذر هذا الحجم) لذلك ليس من السهل على حل جميع المشاكل على طول الطريق، ولكن من الممكن نهائيا (وإلا كيف فإنه يعمل في المقام الأول؟!)

وبمجرد canonalized أسماء الملفات بشكل صحيح مقارنة سلسلة بسيطة تتيح لك الإجابة الصحيحة.

وراسموس الجواب هو على الأرجح أسرع طريقة إذا كنت لا تحتاج إلى مقارنة بنفس أسماء مرارا وتكرارا.

هل يمكن دائما إجراء تشفير MD5 على حد سواء، ومقارنة النتائج. ليست فعالة تماما، ولكن أسهل من يدويا مقارنة ملفات نفسك.

وهنا هي وظيفة على كيفية MD5 سلسلة في C # .

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top