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



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


гарантирует ли этот метод допустимое имя файла в Windows?

612   11  

11 ответов:

учитывая требования, указанные в ранее процитированная документация 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 символов в зависимости от платформы.

недостаточно, в 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 файлы\имя_файла.txt) входит в это количество символов.

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

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

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;
}

что вы думаете?

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

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

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

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

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

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

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

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

публикация нового ответа, потому что у меня нет порога репутации, чтобы комментировать Eng.Код Фуада

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

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

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

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

  • (больше)

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

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

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

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

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

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
    }
  }

выглядит хорошо. По крайней мере, если верить этому ресурсу: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();
}

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

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

  1. имя-это не только точки
  2. имена устройств Windows, такие как AUX, CON, NUL, PRN, COM1, COM2, COM3, ПОРТ COM4, COM5, СОМ6, РЕЗОЛЮЦИЮ COM7, COM8, COM9, ТО ПОРТ LPT1, LPT2 В, ПОДКЛЮЧЕН К ПОРТУ LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9, не может использоваться ни для имени файла, ни для первый сегмент имени файла (т. е. test1 in тест1.формат txt.)
  3. имена устройств не учитывают регистр. (т. е. prn, PRN, Prn и т. д. являются идентичный.)
  4. все символы, превышающие ASCII 31, за исключением "*/:?\ /

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

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

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

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

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

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

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

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

Comments

    Ничего не найдено.