Frage

In der kommenden Java7 gibt es ein neuer API überprüfen, ob zwei Dateiobjektverweis derselben Datei ist.

Gibt es Ähnliche API in dem .NET-Framework zur Verfügung gestellt?

Ich habe die Suche es über MSDN, aber nichts erleuchte mich.

Ich will es einfach, aber ich will nicht nach Dateinamen vergleichen, die Probleme mit harten / symbolischen Links und anderem Stil des Weges führen wird. (Z.B. \\?\C:\, C:\).

Was ich gerade zu tun, gehen wird duplizierten Datei wird per Drag verhindern und fiel auf meine Linkliste.

War es hilfreich?

Lösung

Soweit ich sehen kann, (1) (2) (3) (4) , die Art und Weise JDK7 es tut, ist durch den Aufruf von GetFileInformationByHandle auf die Dateien und dwVolumeSerialNumber, nFileIndexHigh und nFileIndexLow verglichen wird.

Per MSDN:

  

Sie können die VolumeSerialNumber und Fileindex Mitglieder vergleichen in der BY_HANDLE_FILE_INFORMATION Struktur zurückgegeben, um zu bestimmen, ob zwei Pfade zu demselben Ziel abzubilden; zum Beispiel können Sie zwei Dateipfade vergleichen und festzustellen, ob sie in das gleiche Verzeichnis zuordnen.

Ich glaube nicht, diese Funktion von .NET gewickelt ist, so dass Sie verwenden müssen

Andere Tipps

Bearbeiten : Beachten Sie, dass @Rasmus Faber die GetFileInformationByHandle Funktion in dem Win32-API, und das tut, was Sie wollen , überprüfen und seine beantworten, um weitere Informationen .


Ich denke, Sie eine OS-Funktion benötigen Sie die Informationen, die Sie wünschen, andernfalls es einige falsch-negative Ergebnisse haben wird, was auch immer Sie tun.

Zum Beispiel bezieht sich diese auf die gleiche Datei?

  • \ server \ share \ Pfad \ filename.txt
  • \ server \ d $ \ temp \ Pfad \ filename.txt

Ich würde prüfen, wie wichtig es ist, nicht für Sie doppelte Dateien in Ihrer Liste haben, und dann nur einig Best-Effort tun.

Having said that, gibt es ein Verfahren in der Path-Klasse ist, die einen Teil der Arbeit tun können:

Antwort: Es gibt keine absolut sichere Art und Weise, in der Sie auf String-Basispfade zu vergleichen, um zu bestimmen, ob sie auf die gleiche Datei verweisen.

Der Hauptgrund ist, dass scheinbar nicht miteinander verbundenen Wege in die exakt gleiche Datei tun zeigen kann auf System Umleitungen (Kreuzungen, symbolische Links, etc. ...) geltend machen. Zum Beispiel

"d: \ temp \ foo.txt" "C: \ othertemp \ foo.txt"

Diese Pfade können möglicherweise auf die gleiche Datei verweisen. Dieser Fall beseitigt eindeutig eine beliebige Zeichenfolge Vergleichsfunktion als Grundlage für die Bestimmung, ob zwei Pfade auf die gleiche Datei verweisen.

Die nächste Stufe ist der Vergleich der OS-Dateiinformationen. Öffnen Sie die Datei für zwei Pfade und vergleichen Sie den Griff Informationen. In Windows kann dies mit GetFileInformationByHandle erfolgen. Lucian Wischik hat ausgezeichnete Geben Sie hier zu diesem Thema.

Es ist immer noch ein Problem mit diesem Ansatz though. Es funktioniert nur, wenn das Benutzerkonto Durchführung der Überprüfung der Lage ist, beide Dateien zu öffnen, zu lesen. Es gibt zahlreiche Elemente, die einen Benutzer Öffnen einer oder beiden Dateien verhindern. Einschließlich, aber nicht beschränkt auf ...

  • Keine ausreichenden Berechtigungen für Datei
  • Keine ausreichenden Berechtigungen auf ein Verzeichnis in dem Pfad der Datei
  • Dateisystemänderung, die zwischen der Öffnung der ersten Datei und der zweiten wie eine Netzwerktrennung auftritt.

Wenn Sie beginnen, all diese Probleme suchen Sie beginnen zu verstehen, warum Windows bietet keine Methode, um zu bestimmen, ob zwei Pfade gleich sind. Es ist einfach nicht leicht / mögliche Frage zu beantworten.

Hier ist eine C # -Implementierung von IsSameFile mit 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;
    }
  }
}

Zuerst dachte ich, es ist wirklich einfach, aber das nicht Arbeit:

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

Vielleicht ist diese Bibliothek hilft http://www.codeplex.com/FileDirectoryPath . Ich habe es selbst nicht verwendet.

Bearbeiten Sehen Sie dieses Beispiel auf dieser Website:

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

Wenn Sie die gleichen Dateinamen immer und immer wieder vergleichen müssen, würde ich Sie sehen vorschlagen in diese Namen canonalizing.

Unter einem Unix-System gibt es die realpath () Funktion, die Ihren Weg canonalizes. Ich denke, dass ist in der Regel die beste Wahl, wenn Sie einen Komplex haben Pfad. Es ist jedoch wahrscheinlich auf Volumes über Netzwerkverbindungen montiert zum Scheitern verurteilt.

Allerdings basierte auf dem realpath () Ansatz, wenn Sie mehrere Volumen einschließlich Netzwerk-Volumes unterstützen mögen, können Sie Ihre eigene Funktion schreiben, die jeden Verzeichnisnamen in einem Pfad überprüft und wenn es ein Volumen verweist dann bestimmen, ob das Volumen Referenz in beiden Wegen die gleiche ist. Nachdem dies gesagt ist, der Mount-Punkt unterschiedlich sein kann (dh der Pfad auf dem Zielvolume nicht die Wurzel dieses Volumens sein kann), so ist es nicht so einfach, alle Probleme auf dem Weg zu lösen, aber es ist definitiv möglich (sonst wie wäre es in erster Linie arbeiten?!)

Wenn die Dateinamen richtig canonalized ein einfacher String-Vergleich gibt Ihnen die richtige Antwort.

Rasmus Antwort ist wahrscheinlich der schnellste Weg, wenn Sie die gleichen Dateinamen immer und immer wieder nicht vergleichen müssen.

Sie können immer einen MD5 kodieren sowohl durchführen und das Ergebnis vergleichen. Nicht gerade effizient, aber einfacher als die Dateien manuell selbst verglichen wird.

Hier ist ein Beitrag auf , wie eine Zeichenfolge in C # MD5.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top