Java - Как узнать, действительно ли имя файла?
В моем приложении Java я переименовываю файлы в имя файла, представленное в параметре String. Существует метод
boolean OKtoRename(String oldName, String newName)
который в основном проверяет, не является ли newName еще не каким-то другим файлом, так как я бы не захотел похоронить существующие.
Теперь мне пришло в голову, что, возможно, newName String не будет обозначать допустимое имя файла. Поэтому я решил добавить эту проверку к методу:
if (new File(newName).isFile()) {
return false;
}
Очевидно, что это неправильный способ сделать это, так как в большинстве случаев newFile еще не существует и поэтому, хотя это OKtoRename, функция возвращает false.
Мне было интересно, есть ли метод (я знаю, что нет для объектов java.io.File), например canExist()
? Или мне придется прибегать к регулярному выражению, чтобы убедиться, что newFile String не содержит недопустимых символов (например?, *, ",:)? Интересно, есть ли какая-то функция, скрытая где-то в JDK, которая скажет мне, если строка может означать действительное имя файла.
Ответы
Ответ 1
Используйте createNewFile()
, который будет атомизировать файл, только если он еще не существует.
Если файл создан, имя является допустимым и не сбивает существующий файл. Затем вы можете открывать файлы и эффективно копировать данные из одного в другое с помощью операций FileChannel.transferXXX
.
Важно помнить, что в общем случае проверка и создание должны быть атомарными. Если вы сначала проверите, безопасна ли операция, затем выполните операцию как отдельный шаг, условия могут быть изменены в то же время, что делает операцию небезопасной.
Дополнительную информацию о пищу можно найти в этой связанной записи: "Операции перемещения/копирования на Java" .
Update:
После этого ответа были введены API NIO.2, которые добавляют больше взаимодействия с файловой системой.
Предположим, что у вас есть интерактивная программа и вы хотите проверить после каждого нажатия клавиши, является ли файл потенциально допустимым. Например, вы можете включить кнопку "Сохранить" только тогда, когда запись будет действительной, а не появится диалоговое окно с сообщением об ошибке после нажатия "Сохранить". Создание и обеспечение удаления большого количества ненужных файлов, которые потребуются моему предложению выше, похоже на беспорядок.
С NIO.2 вы не можете создать экземпляр Path
, содержащий символы, которые являются незаконными для файловой системы. InvalidPathException
создается, как только вы пытаетесь создать Path
.
Однако API не проверяет незаконные имена, состоящие из допустимых символов, таких как "PRN" в Windows. В качестве обходного пути экспериментирование показало, что использование недопустимого имени файла приведет к возникновению отдельного исключения при попытке доступа к атрибутам (например, с помощью Files.getLastModifiedTime()
).
Если вы укажете юридическое имя для файла, который существует, вы не получите никакого исключения.
Если вы укажете юридическое имя файла, который не существует, он вызывает NoSuchFileException
.
Если вы укажете незаконное имя, FileSystemException
будет поднят.
Однако это кажется очень kludgey и может быть ненадежным в других операционных системах.
Ответ 2
Я собрал список незаконных имен файлов (с учетом UNIX, Mac OS X и систем Windows) на основе некоторых онлайн-исследований пару месяцев назад. Если новое имя файла содержит какие-либо из них, существует риск, что он может быть недействительным на всех платформах.
private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' };
EDIT:
Я хотел бы подчеркнуть, что это не полное решение: как отметил комментатор, даже несмотря на то, что он прошел этот тест, ваше имя файла все равно может быть ключевым для Windows, например COM, PRN и т.д. Однако, если ваше имя файла содержит любой из этих символов, это, безусловно, вызовет проблемы в межплатформенной среде.
Ответ 3
Здесь предлагается конкретный способ системы.
public static boolean isFilenameValid(String file) {
File f = new File(file);
try {
f.getCanonicalPath();
return true;
} catch (IOException e) {
return false;
}
}
Ответ 4
Вот как я это сделал:
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;
}
Ответ 5
Если вы разрабатываете для Eclipse, проверьте 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;
}
}
Ответ 6
Мне кажется, что это проблема, зависящая от ОС. Вы можете просто захотеть проверить наличие недопустимого символа в имени файла. Windows делает это при попытке переименования файла, появляется сообщение о том, что файл не может содержать ни один из следующих символов: \/: *? < > |
Я не уверен, что ваш вопрос: "Есть ли библиотека для меня?" в этом случае я не знаю.
Ответ 7
Просто что-то я нашел, в java 7 и более поздних версиях существует класс под названием Paths
, у которого есть метод под названием get
, который принимает один или несколько String
и бросает
InvalidPathException
- если строка пути не может быть преобразована в Path
Ответ 8
Используя
String validName = URLEncoder.encode( fileName , "UTF-8");
File newFile = new File( validName );
Работает ли.
Я только что нашел сегодня. Я не уверен, работает ли он в 100% случаев, но до сих пор мне удалось создать правильные имена файлов.