Подтвердить что ты не робот

Проверка имени файла в Windows

public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile("^[^/./\\:*?\"<>|]+$");
    Matcher matcher = pattern.matcher(text);
    boolean isMatch = matcher.matches();
    return isMatch;
}

Предоставляет ли этот метод действительное имя файла в Windows?

4b9b3361

Ответ 1

Учитывая требования, указанные в предыдущей цитированной документации MSDN, следующее регулярное выражение должно выполнять довольно хорошую работу:

public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile(
        "# Match a valid Windows filename (unspecified file system).          \n" +
        "^                                # Anchor to start of string.        \n" +
        "(?!                              # Assert filename is not: CON, PRN, \n" +
        "  (?:                            # AUX, NUL, COM1, COM2, COM3, COM4, \n" +
        "    CON|PRN|AUX|NUL|             # COM5, COM6, COM7, COM8, COM9,     \n" +
        "    COM[1-9]|LPT[1-9]            # LPT1, LPT2, LPT3, LPT4, LPT5,     \n" +
        "  )                              # LPT6, LPT7, LPT8, and LPT9...     \n" +
        "  (?:\\.[^.]*)?                  # followed by optional extension    \n" +
        "  $                              # and end of string                 \n" +
        ")                                # End negative lookahead assertion. \n" +
        "[^<>:\"/\\\\|?*\\x00-\\x1F]*     # Zero or more valid filename chars.\n" +
        "[^<>:\"/\\\\|?*\\x00-\\x1F\\ .]  # Last char is not a space or dot.  \n" +
        "$                                # Anchor to end of string.            ", 
        Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS);
    Matcher matcher = pattern.matcher(text);
    boolean isMatch = matcher.matches();
    return isMatch;
}

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

Ответ 2

Недостаточно, в Windows и DOS некоторые слова также могут быть зарезервированы и не могут использоваться как имена файлов.

CON, PRN, AUX, CLOCK$, NUL
COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.

См ~

http://en.wikipedia.org/wiki/Filename


Edit:

Обычно Windows ограничивает имена файлов символами 260. Но имя файла должно быть на самом деле короче, так как полный путь (например, C:\Program Files\filename.txt) включен в этот символ.

Вот почему вы иногда можете столкнуться с ошибкой при копировании файла с очень длинным именем файла в местоположение, имеющее более длинный путь, чем его текущее местоположение.

Ответ 3

Ну, я думаю, что следующий метод гарантировал бы правильное имя файла:

public static boolean isValidName(String text)
{
    try
    {
        File file = new File(text);
        file.createNewFile();
        if(file.exists()) file.delete();
        return true;
    }
    catch(Exception ex){}
    return false;
}

Как вы думаете?

Ответ 4

Метод, который гарантирует, что, как правило, имя файла Windows действителен, - что было бы законно создавать файл с таким именем - было бы невозможно реализовать.

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

Ссылка MSDN, указанная в других ответах, указывает, что имя файла Windows не может содержать "Любой другой символ, который не разрешает целевая файловая система". Например, файл, содержащий NUL, будет некорректен для некоторых файловых систем, а также расширит символы Unicode в некоторых старых файловых системах. Таким образом, файл с именем ☃.txt будет действителен в некоторых случаях, но не в других. Поэтому, будет ли гипотетический isValidName(\"☃\") возвращать true, зависит от базовой файловой системы.

Предположим, однако, что такая функция консервативна и требует, чтобы имя файла состояло из печатных символов ASCII. Все современные версии Windows изначально поддерживают форматы файлов NTFS, FAT32 и FAT16, которые принимают имена файлов Unicode. Но могут быть установлены драйверы для произвольных файловых систем, и каждый может создавать файловую систему, которая не позволяет, например, буквы "n". Таким образом, даже простой файл типа snowman.txt не может быть "гарантирован" действительным.

Но даже с крайними случаями в стороне есть другие осложнения. Например, файл с именем "$ LogFile" не может существовать в корневом томе NTFS, но может существовать в другом месте на томе. Таким образом, не зная директорию, мы не можем знать, является ли "$ LogFile" допустимым именем. Но даже "C:\data\$LogFile" может быть недействительным, если, скажем, "c:\data \" является символической ссылкой на другой корень тома NTFS. (Аналогично, "D:\$LogFile" может быть действительным, если D: является псевдонимом для подкаталога тома NTFS.)

Есть еще больше осложнений. Альтернативные потоки данных в файлах, например, легальны для томов NTFS, поэтому "snowman.txt: ☃" может быть действительным. Все три основные файловые системы Windows имеют ограничения длины пути, поэтому действительность имени файла также зависит от пути. Но длина физического пути может быть даже недоступна для isValidName, если путь является виртуальным псевдонимом, сопоставленным сетевым диском или символической ссылкой, а не физическим путем на томе.

Некоторые другие предложили альтернативу: создайте файл по предлагаемому имени и затем удалите его, вернув true тогда и только тогда, когда создание будет успешным. Этот подход имеет несколько практических и теоретических проблем. Один, как указано выше, заключается в том, что действительность является функцией как имени файла, так и пути, поэтому действительность c:\test\☃.txt может отличаться от действительности c:\test2\☃.txt. Кроме того, функция не сможет записать файл по ряду причин, не связанных с действительностью файла, например, не имея права на запись в каталог. Третий недостаток заключается в том, что не требуется недетерминированность имени файла: гипотетическая файловая система может, например, не разрешать замену удаляемого файла или (теоретически) может даже случайным образом определять, является ли имя файла действительным.

В качестве альтернативы довольно просто создать метод isInvalidFileName(String text), который возвращает значение true, если файл гарантированно недействителен в Windows; имена файлов, такие как "aux", "*" и "abc.txt". вернется. Операция создания файла сначала проверит, что имя файла гарантировано недействительно и, если оно вернет false, остановится. В противном случае метод может попытаться создать файл, будучи подготовленным к граничному случаю, когда файл не может быть создан, потому что имя файла является недопустимым.

Ответ 5

Проводка нового ответа, потому что у меня нет порога rep, чтобы комментировать код Eng.Fouad

public static boolean isValidName(String text)
{
    try
    {
        File file = new File(text);
        if(file.createNewFile()) file.delete();
        return true;
    }
    catch(Exception ex){}
    return false;
}

Небольшое изменение в вашем ответе, которое предотвращает удаление ранее существующего файла. Файлы удаляются только в том случае, если они были созданы во время этого вызова метода, тогда как возвращаемое значение одинаков.

Ответ 6

Здесь вы можете найти, какие имена файлов разрешены.

Следующие символы не допускаются:

  • < (меньше)
  • (больше)

  • : (двоеточие)
  • "(двойная кавычка)
  • /(косая черта)
  • \(обратная косая черта)
  • | (вертикальный стержень или труба)
  • ? (вопросительный знак)
  • * (звездочка)

  • Целочисленное значение ноль, иногда называемое символом NULL ASCII.

  • Символы, чьи целые представления находятся в диапазоне от 1 до 31, за исключением альтернативных потоков данных, где эти символы разрешены. Дополнительные сведения о потоках файлов см. В разделе "Файловые потоки".
  • Любой другой символ, который не разрешает целевая файловая система.

Ответ 7

Выглядит хорошо. По крайней мере, если мы вернем этому ресурсу: http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx

Но я бы упростил использование кода. Достаточно найти один из этих символов, чтобы сказать, что имя недопустимо, поэтому:

public static boolean isValidName(String text)
{
    Pattern pattern = Pattern.compile("[^/./\\:*?\"<>|]");
    return !pattern.matcher(text).find();
}

Это регулярное выражение проще и будет работать быстрее.

Ответ 8

Это решение будет проверять, действительно ли данное имя файла соответствует действующим правилам ОС без создания файла.

Вам все равно нужно обрабатывать другие сбои при фактическом создании файла (например, недостаточные разрешения, нехватка места на диске, ограничения безопасности).

import java.io.File;
import java.io.IOException;

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

  public static void main(String args[]) throws Exception {
    // true
    System.out.println(FileUtils.isFilenameValid("well.txt"));
    System.out.println(FileUtils.isFilenameValid("well well.txt"));
    System.out.println(FileUtils.isFilenameValid(""));

    //false
    System.out.println(FileUtils.isFilenameValid("test.T*T"));
    System.out.println(FileUtils.isFilenameValid("test|.TXT"));
    System.out.println(FileUtils.isFilenameValid("te?st.TXT"));
    System.out.println(FileUtils.isFilenameValid("con.TXT")); // windows
    System.out.println(FileUtils.isFilenameValid("prn.TXT")); // windows
    }
  }

Ответ 9

Не знаю, как реализовать его в Java (либо в Regex, либо в собственном методе). Но ОС Windows имеет следующие правила для создания файла/каталога в файловой системе:

  • Имя не только Точки
  • Названия устройств Windows, такие как AUX, CON, NUL, PRN, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, не могут использоваться для имени файла или для первый сегмент имени файла (то есть test1 в файле test1.txt).
  • Имена устройств нечувствительны к регистру. (т.е. prn, PRN, Prn и т.д. идентичны.)
  • Все символы, превышающие ASCII 31, будут использоваться, кроме "*/: < > ?\|

Итак, программа должна придерживаться этих правил. Надеюсь, он охватывает правила проверки для вашего вопроса.

Ответ 10

Вы можете проверить все зарезервированные имена (AUX, CON и т.п.), а затем использовать этот код:

bool invalidName = GetFileAttributes(name) == INVALID_FILE_ATTRIBUTES && 
        GetLastError() == ERROR_INVALID_NAME;

чтобы проверить любое дополнительное ограничение. Но обратите внимание, что если вы проверите имя в несуществующем каталоге, вы получите сообщение ERROR_PATH_NOT_FOUND, действительно ли это имя или нет.

В любом случае, вы должны помнить старую поговорку:

Проще просить прощения, чем получить разрешение.

Ответ 11

Как насчет того, чтобы класс File выполнил вашу проверку?

public static boolean isValidName(String text) {
    try {
        File file = new File(text);
        return file.getPath().equals(text);
    }
    catch(Exception ex){}
    return false;
}