Java – Как узнать, допустимо ли имя файла?[дубликат]

StackOverflow https://stackoverflow.com/questions/893977

  •  23-08-2019
  •  | 
  •  

Вопрос

В моем приложении Java я переименовываю файлы в имя файла, указанное в параметре String.Существует метод

boolean OKtoRename(String oldName, String newName)

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

Теперь мне пришло в голову, что, возможно, строка newName не будет обозначать допустимое имя файла.Поэтому я решил добавить эту проверку в метод:

if (new File(newName).isFile()) { 
    return false; 
}

Это, очевидно, неправильный способ сделать это, поскольку в большинстве случаев новый файл еще не существует и, следовательно, хотя он является OKtoRename, функция возвращает false.

Мне было интересно, есть ли метод (я знаю, что его нет для объектов java.io.File), например canExist()?Или мне придется прибегнуть к регулярному выражению, чтобы убедиться, что строка newFile не содержит недопустимых символов (например,?, *, ", :)?Интересно, есть ли где-нибудь в JDK спрятанная функция, которая сообщала бы мне, может ли строка обозначать допустимое имя файла.

Это было полезно?

Решение

Использовать createNewFile(), который автоматически создаст файл, только если он еще не существует.

Если файл создан, имя допустимо и не затирает существующий файл.Затем вы можете открыть файлы и эффективно копировать данные из одного в другой с помощью FileChannel.transferXXX операции.

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

Дополнительную пищу для размышлений можно найти в этом соответствующем посте: «Операции перемещения/копирования в Java».


Обновлять:

После этого ответа были представлены API-интерфейсы NIO.2, которые добавляют больше взаимодействия с файловой системой.

Предположим, у вас есть интерактивная программа, и вы хотите после каждого нажатия клавиши проверять, является ли файл потенциально действительным.Например, вы можете захотеть активировать кнопку «Сохранить» только тогда, когда запись действительна, а не открывать диалоговое окно с ошибкой после нажатия «Сохранить».Создание и обеспечение удаления большого количества ненужных файлов, которое потребует мое предложение выше, кажется беспорядком.

С NIO.2 вы не можете создать Path экземпляр, содержащий символы, недопустимые для файловой системы.Ан InvalidPathException возникает, как только вы пытаетесь создать Path.

Однако не существует API для проверки недопустимых имен, состоящих из допустимых символов, например «PRN» в Windows.В качестве обходного пути эксперименты показали, что использование недопустимого имени файла вызовет явное исключение при попытке доступа к атрибутам (с использованием Files.getLastModifiedTime(), например).

Если вы укажете допустимое имя для файла, который существует, вы не получите никаких исключений.

Если вы укажете допустимое имя для файла, который не существует, это вызовет NoSuchFileException.

Если вы укажете недопустимое имя, FileSystemException Поднялся.

Однако это кажется очень громоздким и может быть ненадежным в других операционных системах.

Другие советы

Я собрал список недопустимых символов в именах файлов (учитывая системы UNIX, Mac OS X и Windows) на основе онлайн-исследований, проведенных пару месяцев назад.Если новое имя файла содержит что-либо из этого, существует риск того, что оно может быть недействительным на всех платформах.

private static final char[] ILLEGAL_CHARACTERS = { '/', '\n', '\r', '\t', '\0', '\f', '`', '?', '*', '\\', '<', '>', '|', '\"', ':' };

РЕДАКТИРОВАТЬ:Я хотел бы подчеркнуть, что это не полное решение:как отметил комментатор, даже если он пройдет этот тест, ваше имя файла все равно может быть ключевым словом, специфичным для Windows, например COM, PRN и т. д.Однако если имя вашего файла содержит какой-либо из этих символов, это наверняка вызовет проблемы в кроссплатформенной среде.

Здесь предлагается специфичный для системы способ.

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

Если вы разрабатываете для 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;
   }
}

Вот как я это реализовал:

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

Мне кажется, это проблема, зависящая от ОС.Возможно, вы просто захотите проверить наличие недопустимых символов в имени файла.Windows делает это, когда вы пытаетесь переименовать файл, выдает сообщение о том, что файл не может содержать ни один из следующих символов:\ / :* ?<> | Я не уверен, что ваш вопрос: «Есть ли библиотека для меня?» В этом случае я ничего не знаю.

Я просто кое-что нашел: в Java 7 и более поздних версиях есть класс под названием Paths у которого есть метод под названием get это занимает один или несколько Stringи бросает

InvalidPathException - если строка пути не может быть преобразована в путь

С использованием

String validName = URLEncoder.encode( fileName , "UTF-8");

File newFile = new File( validName );

Делает свою работу.

Я только сегодня нашел.Я не уверен, что это работает в 100% случаев, но до сих пор мне удавалось создавать действительные имена файлов.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top