Перейти к основному содержимому

Проверить строку как имя файла в Java

· 5 мин. чтения

1. Обзор

В этом руководстве мы обсудим различные способы проверки того, имеет ли данная строка допустимое имя файла для ОС, используя Java . Мы хотим проверить значение на соответствие ограниченным символам или ограничениям по длине.

В примерах мы просто сосредоточимся на основных решениях, не используя никаких внешних зависимостей. Мы проверим пакеты SDK java.io и NIO2 и, наконец, реализуем собственные решения.

2. Использование java.io.File

Начнем с самого первого примера, используя класс java.io.File . В этом решении нам нужно создать экземпляр File с заданной строкой, а затем создать файл на локальном диске:

public static boolean validateStringFilenameUsingIO(String filename) throws IOException {
File file = new File(filename);
boolean created = false;
try {
created = file.createNewFile();
return created;
} finally {
if (created) {
file.delete();
}
}
}

Когда данное имя файла неверно, он генерирует исключение IOException . Отметим, что из-за создания файла внутри этот метод требует, чтобы заданная строка имени файла не соответствовала уже существующему файлу. ``

Мы знаем, что разные файловые системы имеют свои собственные ограничения на имена файлов . Таким образом, используя методы java.io.File , нам не нужно указывать правила для каждой ОС , потому что Java автоматически позаботится об этом за нас.

Однако нам нужно создать фиктивный файл. Когда нам это удастся, мы должны не забыть удалить его в конце. ** ** Более того, мы должны убедиться, что у нас есть соответствующие разрешения для выполнения этих действий. Любые сбои также могут вызвать IOException , поэтому также лучше проверить сообщение об ошибке:

// Windows invalid filename
assertThatThrownBy(() -> validateStringFilenameUsingIO("foreach?.txt"))
.isInstanceOf(IOException.class)
.hasMessageContaining("Invalid file path");

3. Использование API NIO2

Как мы знаем, у пакета java.io много недостатков , потому что он создавался в первых версиях Java. API NIO2, преемник пакета java.io , содержит множество улучшений, которые также значительно упрощают наше предыдущее решение:

public static boolean validateStringFilenameUsingNIO2(String filename) {
Paths.get(filename);
return true;
}

Теперь наша функция оптимизирована, так что это самый быстрый способ выполнить такой тест. Мы не создаем никаких файлов, поэтому нам не нужно иметь никаких прав доступа к диску и выполнять очистку после теста.

Недопустимое имя файла вызывает InvalidPathException , которое расширяет RuntimeException . Сообщение об ошибке также содержит больше деталей , чем предыдущее:

// Windows invalid filename
assertThatThrownBy(() -> validateStringFilenameUsingNIO2(filename))
.isInstanceOf(InvalidPathException.class)
.hasMessageContaining("character not allowed");

У этого решения есть один серьезный недостаток, связанный с ограничениями файловой системы . Класс Path может представлять путь к файлу с подкаталогами. В отличие от первого примера, этот метод не проверяет ограничение на переполнение имени файла. Давайте сравним его со случайной строкой из пятисот символов , сгенерированной с помощью метода randomAlphabetic() из Apache Commons:

String filename = RandomStringUtils.randomAlphabetic(500);
assertThatThrownBy(() -> validateStringFilenameUsingIO(filename))
.isInstanceOf(IOException.class)
.hasMessageContaining("File name too long");

assertThat(validateStringFilenameUsingNIO2(filename)).isTrue();

Чтобы исправить это, мы должны, как и раньше, создать файл и проверить результат.

4. Пользовательские реализации

Наконец, давайте попробуем реализовать нашу собственную пользовательскую функцию для проверки имен файлов. Мы также постараемся избежать каких-либо функций ввода-вывода и использовать только основные `` методы Java.

Такие решения дают больше контроля и позволяют нам применять собственные правила . Однако мы должны учитывать множество дополнительных ограничений для различных систем.

4.1. Использование String.contains

Мы можем использовать метод String.contains () , чтобы проверить, содержит ли данная строка какой-либо из запрещенных символов. Прежде всего, нам нужно вручную указать некоторые примерные значения:

public static final Character[] INVALID_WINDOWS_SPECIFIC_CHARS = {'"', '*', ':', '<', '>', '?', '\\', '|', 0x7F};
public static final Character[] INVALID_UNIX_SPECIFIC_CHARS = {'\000'};

В нашем примере давайте сосредоточимся только на этих двух ОС. Как мы знаем, имена файлов в Windows более ограничены, чем в UNIX . Кроме того, некоторые пробельные символы могут быть проблематичными .

После определения ограниченных наборов символов давайте определим текущую ОС:

public static Character[] getInvalidCharsByOS() {
String os = System.getProperty("os.name").toLowerCase();
if (os.contains("win")) {
return INVALID_WINDOWS_SPECIFIC_CHARS;
} else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) {
return INVALID_UNIX_SPECIFIC_CHARS;
} else {
return new Character[]{};
}
}

И теперь мы можем использовать его для проверки заданного значения:

public static boolean validateStringFilenameUsingContains(String filename) {
if (filename == null || filename.isEmpty() || filename.length() > 255) {
return false;
}
return Arrays.stream(getInvalidCharsByOS())
.noneMatch(ch -> filename.contains(ch.toString()));
}

Этот предикат Stream возвращает значение true, если какой-либо из определенных нами символов отсутствует в заданном имени файла. Кроме того, мы реализовали поддержку нулевых значений и неправильной длины.

4.2. Сопоставление шаблонов регулярных выражений

Мы также можем использовать регулярные выражения непосредственно для заданной строки . Давайте реализуем шаблон, принимающий только буквенно-цифровые и точечные символы, длиной не более 255:

public static final String REGEX_PATTERN = "^[A-za-z0-9.]{1,255}$";

public static boolean validateStringFilenameUsingRegex(String filename) {
if (filename == null) {
return false;
}
return filename.matches(REGEX_PATTERN);
}

Теперь мы можем проверить заданное значение на заранее подготовленном шаблоне. Мы также можем легко изменить шаблон. В этом примере мы пропустили функцию проверки ОС.

5. Вывод

В этой статье мы сосредоточились на именах файлов и их ограничениях. Мы представили различные алгоритмы для обнаружения недопустимого имени файла с помощью Java.

Мы начали с пакета java.io , который заботится о большинстве системных ограничений, но выполняет дополнительные действия ввода-вывода и может потребовать некоторых разрешений. Затем мы проверили NIO2 API, который является самым быстрым решением, с ограничением проверки длины имени файла .

Наконец, мы реализовали собственные методы, не используя API ввода-вывода, но требуя пользовательской реализации правил файловой системы .

Вы можете найти все примеры с дополнительными тестами на GitHub .