2009-05-21 10 views
45

W mojej aplikacji Java zmieniam nazwę pliku na nazwę pliku podaną w parametrze String. Jest to metodaJava - Jak sprawdzić, czy nazwa pliku jest poprawna?

boolean OKtoRename(String oldName, String newName) 

które zasadniczo sprawdza, czy newName nie jest już zajęta przez innego pliku, a nie chciałbym, aby pochować istniejących.

Teraz przyszło mi do głowy, że być może ciąg newName nie będzie oznaczać prawidłowej nazwy pliku. Więc pomyślałem, aby dodać tę kontrolę metody:

if (new File(newName).isFile()) { 
    return false; 
} 

co oczywiście nie jest właściwym sposobem, aby to zrobić, ponieważ w większości przypadków newfile jeszcze nie istnieje i dlatego chociaż jest OKtoRename The funkcja zwraca wartość false.

Zastanawiam się, czy istnieje metoda (wiem, że nie ma obiektów java.io.File) jak canExist()? Czy musiałbym uciekać się do regex, aby upewnić się, że ciąg newFile nie zawiera niepoprawnych znaków (np.?, *, ", :)? Zastanawiam się, czy jest prawdopodobnie funkcja ukryta gdzieś w JDK, która powie mi, czy ciąg znaków mogłaby oznaczać poprawną nazwę pliku.

+0

proszę, nie więcej istnieje() odpowiedzi, to nie jest pomocne. Próbuję sprawdzić, czy plik MOŻE istnieć. –

+1

@MasterPeter: Spróbuj przerobić swoje pytanie. Wygląda tak, jakbyś chciał wiedzieć, czy plik istnieje, kiedy to, czego potrzebujesz, to wiedzieć, czy plik NAZWA jest poprawny. Zmieniłem tytuł, ale nie dotknąłem tekstu pytania. – OscarRyz

+0

Wydaje się istotne: http://eng-przemelek.blogspot.com/2009/07/how-to-create-valid-file-name.html – greenoldman

Odpowiedz

21

Korzystając createNewFile(), który niepodzielnie utworzyć plik tylko wtedy, gdy jeszcze nie istnieje.

Jeśli zostanie utworzony plik, nazwa jest poprawna i nie jest clobbering Istniejący plik można następnie otwierać i efektywnie kopiować dane z jednego do drugiego przy pomocy operacji FileChannel.transferXXX.

Należy pamiętać, że na ogół kontrola i stworzenie powinno być atomowe. Jeśli najpierw sprawdzisz, czy operacja jest bezpieczna, wykonaj operację jako oddzielny krok, w międzyczasie warunki mogły ulec zmianie, co czyni operację niebezpieczną.

dodatkowy materiał do przemyśleń jest dostępna w tym powiązanej postu: "Move/Copy operations in Java."


Aktualizacja:

Od tej odpowiedzi, API NIO.2 zostały wprowadzone, co dodać więcej interakcji z system plików.

Załóżmy, że masz interaktywny program i chcesz sprawdzić po każdym naciśnięciu klawisza, czy plik jest potencjalnie ważny. Na przykład możesz chcieć włączyć przycisk "Zapisz" tylko wtedy, gdy wpis jest prawidłowy, zamiast pojawiać się w oknie dialogowym błędu po naciśnięciu "Zapisz". Tworzenie i zapewnianie usuwania niepotrzebnych plików, których moja sugestia wymagałaby, wydaje się być bałaganem.

Za pomocą NIO.2 nie można utworzyć instancji Path zawierającej znaki, które są niedozwolone dla systemu plików. Numer InvalidPathException jest wywoływany zaraz po próbie utworzenia Path.

Jednak nie ma interfejsu API do sprawdzania nielegalnych nazw składających się z ważnych znaków, takich jak "PRN" w systemie Windows. W ramach obejścia eksperymenty pokazały, że użycie nielegalnej nazwy pliku spowodowałoby wyraźny wyjątek podczas próby uzyskania dostępu do atrybutów (na przykład przy użyciu Files.getLastModifiedTime()).

Jeśli określisz prawną nazwę pliku, który istnieje, nie otrzymasz wyjątku.

Jeśli określisz prawną nazwę pliku, który nie istnieje, powstaje NoSuchFileException.

Jeśli podasz niedozwoloną nazwę, zostanie podniesiona FileSystemException.

Jednak wydaje się to bardzo kludgey i może nie być wiarygodne w innych systemach operacyjnych.

+2

Będziesz jednak chciał usunąć właśnie utworzony plik, ponieważ funkcja OKtoRename nie powinna właściwie zmieniać systemu plików, po prostu odpowiedz, czy nazwa pliku zadziała. –

+1

@Matt: Ooor, po prostu utworzysz plik i jeśli createNewFile zwróci false, oznacza to, że nazwa pliku jest nieprawidłowa (... lub nie może być utworzona: -S) ¬ – OscarRyz

+0

dokładnie, myślę, że pójdę z to rozwiązanie, ale nie podoba mi się pomysł utworzenia pustego pliku tylko po to, aby go natychmiast usunąć ... –

57

Złożyłem listę niedozwolonych nazw plików (biorąc pod uwagę systemy UNIX, Mac OS X i Windows) na podstawie kilku badań online sprzed kilku miesięcy. Jeśli nowa nazwa pliku zawiera którąkolwiek z tych wartości, istnieje ryzyko, że nie będzie ona poprawna na wszystkich platformach.

private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' }; 

EDIT: chciałbym podkreślić, że jest to nie kompletne rozwiązanie: jako komentator zauważył, mimo że przechodzi ten test nazwy pliku nadal może być specyficzny Hasło systemu Windows jak COM, PRN itp. Jednakże, jeśli twoja nazwa pliku zawiera którąkolwiek z tych postaci, z pewnością spowoduje problemy w środowisku wieloplatformowym.

+10

Ale nie zapominaj o słowach kluczowych, takich jak próba utworzenia pliku o nazwie COM, COM1, COM2, PRN itp. (Przynajmniej na platformach Windows) – Instantsoup

+0

Punkt wzięty, nawet o tym nie pomyślał ... –

+1

podczas gdy ja zdaję sobie sprawę To nie jest kompletne rozwiązanie, działa to dla mnie świetnie (gdzie tylko część nazwy pliku jest dynamiczna, a więc słowa kluczowe nie są zagrożeniem). dziękuję za skompilowanie tej listy. – radai

2

Dla mnie wydaje się, że jest to problem zależny od systemu operacyjnego. Możesz po prostu chcieć sprawdzić jakiś nieprawidłowy znak w nazwie pliku. System Windows robi to, próbując zmienić nazwę pliku, wyświetla komunikat, że plik nie może zawierać żadnego z następujących znaków: \ /: *? <> | Nie jestem pewien, czy twoje pytanie brzmi "czy biblioteka wykonuje dla mnie zadanie?" w takim przypadku nie znam żadnego.

+2

należy również sprawdzić długość nazwy pliku. –

0

Korzystanie

String validName = URLEncoder.encode(fileName , "UTF-8"); 

File newFile = new File(validName); 

działa.

Właśnie znalazłem dzisiaj. Nie jestem pewien, czy to działa w 100% przypadków, ale do tej pory udało mi się stworzyć poprawne nazwy plików.

+4

Przepraszam, ale jeśli w nazwie pliku byłyby gwiazdy, twój kod nie pomógłby. System.out.println (URLEncoder.encode ("* hello world *", "UTF-8")); wypisuje * hello + world * A to nie byłaby poprawna nazwa pliku. –

+0

Świetnie! .. Masz rację, właściwie chciałem o to zapytać. :) – OscarRyz

4

To jak ja realizowane w ten sposób: specyficzny sposób układ

public boolean isValidFileName(final String aFileName) { 
    final File aFile = new File(aFileName); 
    boolean isValid = true; 
    try { 
     if (aFile.createNewFile()) { 
      aFile.delete(); 
     } 
    } catch (IOException e) { 
     isValid = false; 
    } 
    return isValid; 
} 
+2

Prowadzi to do błędu zabezpieczenia dostępu do katalogu. Nie jest to bezpieczny sposób kodowania, jeśli nazwa pliku pochodzi od strony trzeciej. –

+0

@VishnuPrasadKallummel Przeniesienie katalogu polega na wykorzystaniu niewystarczającego sprawdzania poprawności/sanityzacji wprowadzanych przez użytkownika nazw plików wejściowych. Powinieneś mieć inną warstwę w swojej aplikacji, aby przeprowadzić sanityzację. Czy możesz wyjaśnić, dlaczego uważasz, że sprawdzanie danych wejściowych przez użytkownika powinno być mieszane w metodzie, która sprawdza, czy dana ścieżka jest ważna? –

+0

Ta metoda będzie stanowić problem z przenoszeniem katalogów. Ale jeśli masz dodatkową warstwę, gdzie sprawdzasz przed wywołaniem tej metody, to wygląda ona dobrze. To był spontaniczny komentarz, ponieważ szukałem tego samego bez tworzenia pliku, a następnie jego usuwania. –

16

Here sugeruje.

public static boolean isFilenameValid(String file) { 
    File f = new File(file); 
    try { 
    f.getCanonicalPath(); 
    return true; 
    } catch (IOException e) { 
    return false; 
    } 
} 
+0

Oh my bad, nie widziałem twojej odpowiedzi ... –

+1

fajne rozwiązanie, ale niestety to nie działa na Androida :-(iefgetCanonicalPath() nie wyrzuca wyjątku dla niepoprawnych nazw plików –

+6

Czy to nie jest ryzykowne polegać na funkcji, która jest [nie stworzona do pracy] (http://docs.oracle.com/javase/7/docs/api/java/io/File.html#getCanonicalFile())? – Nielsvh

4

Jeśli rozwija Eclipse, sprawdź org.eclipse.core.internal.resources.OS

public abstract class OS { 
    private static final String INSTALLED_PLATFORM; 

    public static final char[] INVALID_RESOURCE_CHARACTERS; 
    private static final String[] INVALID_RESOURCE_BASENAMES; 
    private static final String[] INVALID_RESOURCE_FULLNAMES; 

    static { 
     //find out the OS being used 
     //setup the invalid names 
     INSTALLED_PLATFORM = Platform.getOS(); 
     if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) { 
     //valid names and characters taken from http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/naming_a_file.asp 
     INVALID_RESOURCE_CHARACTERS = new char[] {'\\', '/', ':', '*', '?', '"', '<', '>', '|'}; 
     INVALID_RESOURCE_BASENAMES = new String[] {"aux", "com1", "com2", "com3", "com4", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ 
       "com5", "com6", "com7", "com8", "com9", "con", "lpt1", "lpt2", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ 
       "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", "nul", "prn"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ 
     Arrays.sort(INVALID_RESOURCE_BASENAMES); 
     //CLOCK$ may be used if an extension is provided 
     INVALID_RESOURCE_FULLNAMES = new String[] {"clock$"}; //$NON-NLS-1$ 
     } else { 
     //only front slash and null char are invalid on UNIXes 
     //taken from http://www.faqs.org/faqs/unix-faq/faq/part2/section-2.html 
     INVALID_RESOURCE_CHARACTERS = new char[] {'/', '\0',}; 
     INVALID_RESOURCE_BASENAMES = null; 
     INVALID_RESOURCE_FULLNAMES = null; 
     } 
    } 

    /** 
    * Returns true if the given name is a valid resource name on this operating system, 
    * and false otherwise. 
    */ 
    public static boolean isNameValid(String name) { 
     //. and .. have special meaning on all platforms 
     if (name.equals(".") || name.equals("..")) //$NON-NLS-1$ //$NON-NLS-2$ 
     return false; 
     if (INSTALLED_PLATFORM.equals(Platform.OS_WIN32)) { 
     //empty names are not valid 
     final int length = name.length(); 
     if (length == 0) 
      return false; 
     final char lastChar = name.charAt(length-1); 
     // filenames ending in dot are not valid 
     if (lastChar == '.') 
      return false; 
     // file names ending with whitespace are truncated (bug 118997) 
     if (Character.isWhitespace(lastChar)) 
      return false; 
     int dot = name.indexOf('.'); 
     //on windows, filename suffixes are not relevant to name validity 
     String basename = dot == -1 ? name : name.substring(0, dot); 
     if (Arrays.binarySearch(INVALID_RESOURCE_BASENAMES, basename.toLowerCase()) >= 0) 
      return false; 
     return Arrays.binarySearch(INVALID_RESOURCE_FULLNAMES, name.toLowerCase()) < 0; 
     } 
     return true; 
    } 
} 
+2

To jest dostępne poprzez' org.eclipse.core.resources.IWorkspace.validateName (String, int) ' – Basilevs

2

tylko coś znalazłem, w Java 7 i później, istnieje klasa o nazwie Paths że ma metodę zwaną get że ma jedną lub więcej String y i rzuca

InvalidPathException - jeśli ciąg ścieżki nie mogą być konwertowane do ścieżki

+0

warto spróbować –

+0

Jedna rzecz do zapamiętania: na systemy oparte na systemie Unix, są to prawidłowe nazwy plików: "cześć!", "plik cześć", "naprawdę?" W pracy uznano, że takie podejście pozwoliło im przejść. – lordoku

Powiązane problemy