it-swarm.com.de

Gibt es eine Möglichkeit in Java zu ermitteln, ob ein Pfad gültig ist, ohne zu versuchen, eine Datei zu erstellen?

Ich muss feststellen, ob ein vom Benutzer bereitgestellter String ein gültiger Dateipfad ist (dh ob createNewFile () erfolgreich ist oder eine Exception auslöst), aber ich möchte das Dateisystem nicht mit nutzlosen Dateien füllen, die nur für Validierungszwecke erstellt wurden gibt es eine Möglichkeit, festzustellen, ob der String, den ich habe, ein gültiger Dateipfad ist, ohne zu versuchen, die Datei zu erstellen?

Ich weiß, dass die Definition des "gültigen Dateipfads" je nach Betriebssystem unterschiedlich ist, aber ich habe mich gefragt, ob es eine schnelle Möglichkeit gibt, "C:/foo" oder "/ foo" zu akzeptieren und "Banane" abzulehnen ... ein möglicher Ansatz Möglicherweise wird versucht, die Datei zu erstellen und schließlich zu löschen, wenn die Erstellung erfolgreich war, aber ich hoffe, es gibt einen eleganteren Weg, um dasselbe Ergebnis zu erzielen ...

54
Raibaz

Dies würde auch prüfen, ob das Verzeichnis vorhanden ist.

File file = new File("c:\\cygwin\\cygwin.bat");
if (!file.isDirectory())
   file = file.getParentFile();
if (file.exists()){
    ...
}

Es scheint, dass file.canWrite () Ihnen keinen klaren Hinweis gibt, ob Sie über Berechtigungen zum Schreiben in das Verzeichnis verfügen.

26
krosenvold

Die in Java 7 eingeführte Pfadklasse fügt neue Alternativen wie die folgenden hinzu:
(Funktioniert nicht ordnungsgemäß unter Linux - gibt immer "true" zurück)

/**
 * <pre>
 * Checks if a string is a valid path.
 * Null safe.
 *  
 * Calling examples:
 *    isValidPath("c:/test");      //returns true
 *    isValidPath("c:/te:t");      //returns false
 *    isValidPath("c:/te?t");      //returns false
 *    isValidPath("c/te*t");       //returns false
 *    isValidPath("good.txt");     //returns true
 *    isValidPath("not|good.txt"); //returns false
 *    isValidPath("not:good.txt"); //returns false
 * </pre>
 */
public static boolean isValidPath(String path) {
    try {
        Paths.get(path);
    } catch (InvalidPathException | NullPointerException ex) {
        return false;
    }
    return true;
}
26
c0der

File.getCanonicalPath() ist für diesen Zweck sehr nützlich. IO -Ausnahmen werden für bestimmte Typen ungültiger Dateinamen ausgelöst (z. B. CON, PRN, *?* in Windows), wenn das Problem mit dem Betriebssystem oder Dateisystem gelöst wird. Dies dient jedoch nur als Vorprüfung; Sie müssen bei der Erstellung der Datei immer noch andere Fehler beheben (z. B. unzureichende Berechtigungen, nicht genügend Speicherplatz auf dem Laufwerk, Sicherheitsbeschränkungen).

16
Zach Scrivena

Wenn Sie versuchen, eine Datei zu erstellen, können einige Probleme auftreten:

  • Ihnen fehlen die erforderlichen Berechtigungen.
  • Auf dem Gerät ist nicht genügend Speicherplatz vorhanden.
  • Das Gerät hat einen Fehler. 
  • Bestimmte Sicherheitsrichtlinien verhindern, dass Sie eine Datei eines bestimmten Typs erstellen.
  • usw.

Genauer gesagt, diese können sich zwischen dem Versuch und der Abfrage ändern, um zu sehen, ob Sie es können und wann Sie es tatsächlich können. In einer Multithread-Umgebung ist dies eine der Hauptursachen für Race-Bedingungen und kann bei einigen Programmen eine echte Sicherheitsanfälligkeit darstellen.

Im Grunde müssen Sie es nur versuchen und erstellen und sehen, ob es funktioniert. Und das ist der richtige Weg. Aus diesem Grund haben Dinge wie ConcurrentHashMap eine putIfAbsent(), sodass das Prüfen und Einfügen eine atomare Operation ist und keine Race-Bedingungen aufweist. Genau das gleiche Prinzip ist hier im Spiel.

Wenn dies nur ein Teil eines Diagnose- oder Installationsprozesses ist, führen Sie es einfach aus und prüfen Sie, ob es funktioniert. Wieder gibt es keine Garantie, dass es später funktionieren wird.

Grundsätzlich muss Ihr Programm robust genug sein, um ordnungsgemäß zu sterben, wenn es keine relevanten Dateien schreiben kann.

15
cletus

Hier können Sie etwas tun, das für alle Betriebssysteme geeignet ist

Verwenden Sie Regex-Übereinstimmung, um nach vorhandenen bekannten ungültigen Zeichen zu suchen.

if (newName.matches(".*[/\n\r\t\0\f`?*\\<>|\":].*")) {
    System.out.println("Invalid!");
} else {
    System.out.println("Valid!");
}

Pros

  • Dies funktioniert über Betriebssysteme hinweg
  • Sie können ihn beliebig anpassen Sie möchten diesen regulären Ausdruck bearbeiten.

Nachteile

  • Dies ist möglicherweise keine vollständige Liste und erfordert mehr Forschung, um weitere ungültige Muster oder Zeichen auszufüllen.
0
Fangming

Mach es einfach (und räum nach dir auf)

Möglicherweise wird versucht, die Datei zu erstellen und sie schließlich zu löschen, wenn die Erstellung erfolgreich war. Ich hoffe jedoch, dass es eine elegantere Methode gibt, um dasselbe Ergebnis zu erzielen.

Vielleicht ist das der robusteste Weg.

Unten finden Sie canCreateOrIsWritable, die bestimmt, ob Ihr Programm in der Lage ist, eine Datei und ihre übergeordneten Verzeichnisse unter einem bestimmten Pfad zu erstellen oder, falls dort bereits eine Datei vorhanden ist, in diese zu schreiben.

Dazu werden die erforderlichen übergeordneten Verzeichnisse sowie eine leere Datei im Pfad erstellt. Anschließend werden sie gelöscht (wenn im Pfad eine Datei vorhanden war, bleibt diese in Ruhe).

So können Sie es verwenden:

var myFile = new File("/home/me/maybe/write/here.log")

if (canCreateOrIsWritable(myFile)) {
    // We're good. Create the file or append to it
    createParents(myFile);
    appendOrCreate(myFile, "new content");
} else {
    // Let's pick another destination. Maybe the OS's temporary directory:
    var tempDir = System.getProperty("Java.io.tmpdir");
    var alternative = Paths.get(tempDir, "second_choice.log");
    appendOrCreate(alternative, "new content in temporary directory");
}

Die wesentliche Methode mit ein paar Hilfsmethoden:

static boolean canCreateOrIsWritable(File file) {
    boolean canCreateOrIsWritable;

    // The non-existent ancestor directories of the file.
    // The file's parent directory is first
    List<File> parentDirsToCreate = getParentDirsToCreate(file);

    // Create the parent directories that don't exist, starting with the one
    // highest up in the file system hierarchy (closest to root, farthest
    // away from the file)
    reverse(parentDirsToCreate).forEach(File::mkdir);

    try {
        boolean wasCreated = file.createNewFile();
        if (wasCreated) {
            canCreateOrIsWritable = true;
            // Remove the file and its parent dirs that didn't exist before
            file.delete();
            parentDirsToCreate.forEach(File::delete);
        } else {
            // There was already a file at the path → Let's see if we can
            // write to it
            canCreateOrIsWritable = Java.nio.file.Files.isWritable(file.toPath());
        }
    } catch (IOException e) {
        // File creation failed
        canCreateOrIsWritable = false;
    }
    return canCreateOrIsWritable;
}

static List<File> getParentDirsToCreate(File file) {
    var parentsToCreate = new ArrayList<File>();
    File parent = file.getParentFile();
    while (parent != null && !parent.exists()) {
        parentsToCreate.add(parent);

        parent = parent.getParentFile();
    }
    return parentsToCreate;
}

static <T> List<T> reverse(List<T> input) {
    var reversed = new ArrayList<T>();
    for (int i = input.size() - 1; i >= 0; i--) {
        reversed.add(input.get(i));
    }
    return reversed;
}

static void createParents(File file) {
    File parent = file.getParentFile();
    if (parent != null) {
        parent.mkdirs();
    }
}

Beachten Sie, dass sich der Inhalt und die Berechtigungen Ihres Dateisystems zwischen dem Aufrufen von canCreateOrIsWritable und dem Erstellen der eigentlichen Datei möglicherweise geändert haben.

0
Matthias Braun