Java: come scoprire se un nome file è valido?[duplicare]
Domanda
Questa domanda ha già una risposta qui:
Nella mia applicazione Java sto rinominando i file con un nome file fornito in un parametro String.C'è un metodo
boolean OKtoRename(String oldName, String newName)
che fondamentalmente controlla se newName non è già preso da qualche altro file, poiché non vorrei seppellire quelli esistenti.
Ora mi è venuto in mente che forse la stringa newName non indicherà un nome di file valido.Quindi ho pensato di aggiungere questo controllo al metodo:
if (new File(newName).isFile()) {
return false;
}
Il che ovviamente non è il modo giusto, poiché nella maggior parte dei casi il newFile non esiste ancora e quindi pur essendo È OKtoRename, la funzione restituisce false.
Mi chiedevo, esiste un metodo (so che non esiste per gli oggetti java.io.File) come canExist()
?Oppure dovrei ricorrere alla regex per assicurarmi che la newFile String non contenga caratteri non validi (ad es.?, *, ", :)?Mi chiedo se ci sia forse una funzione nascosta da qualche parte nel JDK che mi direbbe se una stringa potrebbe denotare un nome di file valido.
Soluzione
createNewFile()
, che atomicamente creare il file solo se non esiste ancora.
Se il file viene creato, il nome è valido e non è clobbering un file esistente. È quindi possibile aprire i file in modo efficiente e copiare i dati da uno all'altro con le operazioni FileChannel.transferXXX
.
Una cosa importante da tenere a mente che, in generale, il controllo e la creazione dovrebbe essere atomica. Se si seleziona prima se un'operazione è sicuro, quindi eseguire l'operazione in una fase successiva, le condizioni possono essere cambiate nel frattempo, rendendo l'operazione non sicuro.
cibo supplementare di riflessione è disponibile a questo post correlati: "operazioni Sposta / Copia in Java. "
Aggiornamento:
Da questa risposta, sono state introdotte le API NIO.2, che aggiungono una maggiore interazione con il file system.
Supponiamo di avere un programma interattivo, e desidera convalidare dopo ogni pressione del tasto se il file è potenzialmente valido. Ad esempio, si potrebbe desiderare di attivare un pulsante "Salva" solo quando la voce è valida piuttosto che spuntando una finestra di errore dopo aver premuto "Salva". Creazione e garantire l'eliminazione di un sacco di file inutili che il mio suggerimento sopra richiederebbe sembra un pasticcio.
Con NIO.2, non è possibile creare un'istanza Path
contenente caratteri non validi per il file system. Un InvalidPathException
è sollevata, non appena si tenta di creare il Path
.
Tuttavia, non v'è un'API per convalidare i nomi illegali composti da caratteri validi, come "PRN" su Windows. Per risolvere il problema, la sperimentazione ha dimostrato che l'utilizzo di un nome di file illegale avrebbe sollevato un'eccezione distinta quando si cerca di attributi di accesso (usando Files.getLastModifiedTime()
, per esempio).
Se si specifica un nome legale per un file che non esiste, si ottiene non fa eccezione.
Se si specifica un nome legale per un file che non esiste, che solleva NoSuchFileException
.
Se si specifica un nome illegale, FileSystemException
è sollevata.
Tuttavia, questo sembra molto kludgey e potrebbe non essere attendibile su altri sistemi operativi.
Altri suggerimenti
Ho messo insieme un elenco di caratteri illegali nei nomi di file (considerando i sistemi UNIX, Mac OS X e Windows) sulla base di alcune ricerche online un paio di mesi fa.Se il nuovo nome file contiene uno di questi elementi, c'è il rischio che non sia valido su tutte le piattaforme.
private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' };
MODIFICARE:Vorrei sottolineare che è così non una soluzione completa:come ha sottolineato un commentatore, anche se supera questo test, il nome del tuo file potrebbe comunque essere una parola chiave specifica di Windows come COM, PRN, ecc.Tuttavia, se il nome del tuo file contiene uno di questi caratteri, causerà sicuramente problemi in un ambiente multipiattaforma.
Qui sistema modo specifico è suggerito.
public static boolean isFilenameValid(String file) {
File f = new File(file);
try {
f.getCanonicalPath();
return true;
} catch (IOException e) {
return false;
}
}
Se in via di sviluppo per Eclipse, il check out 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;
}
}
Questo è come ho implementato questo:
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;
}
A me sembra che vi sia un problema di dipendenza del sistema operativo. Si può semplicemente voler controllare per qualche carattere non valido nel nome del file. Di Windows fa questo quando si tenta di rinominare il file, si apre un messaggio che dice che un file non può contenere i seguenti caratteri: \ /: *? <> | Io non sono sicuro se la tua domanda è "c'è una biblioteca a fare il lavoro per me?" in quel caso io non conosco nessuna.
Solo qualcosa che ho trovato, in Java 7 e versioni successive, c'è una classe chiamata Paths
che ha un metodo chiamato get
ne servono uno o più String
se lancia
InvalidPathException
- se la stringa del percorso non può essere convertita in un percorso
con
String validName = URLEncoder.encode( fileName , "UTF-8");
File newFile = new File( validName );
fa il lavoro.
Ho appena trovato oggi. Non sono sicuro se funziona al 100% del tempo, ma finora, sono stato in grado di creare i nomi di file validi.