Ich muss feststellen, ob eine vom Benutzer angegebene Zeichenfolge ein gültiger Dateipfad ist (dh ob dies createNewFile()
erfolgreich ist oder eine Ausnahme auslöst), aber ich möchte das Dateisystem nicht mit nutzlosen Dateien aufblähen, die nur zu Validierungszwecken erstellt wurden.
Gibt es eine Möglichkeit festzustellen, ob die Zeichenfolge, die 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, zu akzeptieren C:/foo
oder /foo
abzulehnen banana
.
Ein möglicher Ansatz könnte darin bestehen, die Datei zu erstellen und sie schließlich zu löschen, wenn die Erstellung erfolgreich war. Ich hoffe jedoch, dass es eine elegantere Möglichkeit gibt, dasselbe Ergebnis zu erzielen.
quelle
Antworten:
Dies würde auch die Existenz des Verzeichnisses überprüfen.
File file = new File("c:\\cygwin\\cygwin.bat"); if (!file.isDirectory()) file = file.getParentFile(); if (file.exists()){ ... }
Es scheint, dass file.canWrite () Ihnen keinen eindeutigen Hinweis gibt, ob Sie zum Schreiben in das Verzeichnis berechtigt sind.
quelle
new File("some/path")
. Sie können diese also zu Validierungszwecken verwenden. Um Dateien auf dem Dateisystem zu erstellen, müssencreateNewFile
usw.Die in Java 7 eingeführte Pfadklasse fügt neue Alternativen hinzu, wie die folgenden:
(Funktioniert unter Linux nicht ordnungsgemäß - 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; }
quelle
true
unter Linux zurückgegeben wird. In meinen eigenen TestsPaths.get("file\u0000")
wirft nicht einmalInvalidPathException
.File.getCanonicalPath()
ist für diesen Zweck sehr nützlich. IO Ausnahmen sind für bestimmte Arten von ungültigen Dateinamen (zB geworfenCON
,PRN
,*?*
in Windows) , wenn sie gegen das Betriebssystem oder Dateisystem zu lösen. Dies dient jedoch nur als vorläufige Überprüfung; Sie müssen beim Erstellen der Datei noch andere Fehler behandeln (z. B. unzureichende Berechtigungen, mangelnder Speicherplatz, Sicherheitsbeschränkungen).quelle
Beim Versuch, eine Datei zu erstellen, kann eine Reihe von Fehlern auftreten:
Genauer gesagt können sich diese zwischen dem Versuch und der Abfrage, ob Sie dies können, und dem Zeitpunkt, zu dem Sie es tatsächlich können, ändern. In einer Multithread-Umgebung ist dies eine der Hauptursachen für Rennbedingungen und kann eine echte Sicherheitslücke einiger Programme darstellen.
Grundsätzlich müssen Sie nur versuchen, es zu erstellen und zu sehen, ob es funktioniert. Und das ist der richtige Weg. Aus diesem Grund
ConcurrentHashMap
istputIfAbsent()
das Überprüfen und Einfügen eine atomare Operation und leidet nicht unter den Rennbedingungen. Genau das gleiche Prinzip spielt hier eine Rolle.Wenn dies nur ein Teil eines Diagnose- oder Installationsprozesses ist, tun Sie es einfach und prüfen Sie, ob es funktioniert. Auch hier gibt es keine Garantie, dass es später funktioniert.
Grundsätzlich muss Ihr Programm robust genug sein, um ordnungsgemäß zu sterben, wenn es keine relevante Datei schreiben kann.
quelle
boolean canWrite(File file) { if (file.exists()) { return file.canWrite(); } else { try { file.createNewFile(); file.delete(); return true; } catch (Exception e) { return false; } } }
quelle
File.canWrite()
es unter Windows nicht zuverlässig ist. Eine Problemumgehung finden Sie in diesem Beitrag und im ersten Kommentar von Peter Tseng.Hier ist etwas, das Sie für alle Betriebssysteme tun können
Verwenden der 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!"); }
Vorteile
Nachteile
quelle
Mach es einfach (und räum nach dir auf)
Vielleicht ist das der robusteste Weg.
Im Folgenden wird
canCreateOrIsWritable
festgelegt, ob Ihr Programm eine Datei und ihre übergeordneten Verzeichnisse unter einem bestimmten Pfad erstellen oder, falls dort bereits eine Datei vorhanden ist, in diese Datei schreiben kann.Dazu werden die erforderlichen übergeordneten Verzeichnisse sowie eine leere Datei im Pfad erstellt. Danach werden sie gelöscht (wenn eine Datei im Pfad vorhanden war, wird sie in Ruhe gelassen).
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 zwischen dem Aufrufen
canCreateOrIsWritable
und Erstellen der eigentlichen Datei möglicherweise der Inhalt und die Berechtigungen Ihres Dateisystems geändert haben.quelle