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

Существует ли кросс-платформенный Java-метод для удаления специальных символов в именах файлов?

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

Я знаю, что разные платформы имеют разные требования к именам файлов, поэтому мне было интересно, есть ли кросс-платформенный способ сделать это?

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

Кроме того, я бы предпочел стандартное решение Java, которое не требует сторонних библиотек.

4b9b3361

Ответ 1

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

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

Linux в значительной степени позволяет все, что может быть настоящей болью. Я бы просто ограничил Linux тем же списком, в котором вы ограничиваете Windows, чтобы сохранить свои головные боли в будущем.

С помощью этого фрагмента С# в Windows я создал список символов, которые недействительны в Windows. В этом списке есть еще несколько символов, чем вы думаете (41), поэтому я бы не рекомендовал создавать свой собственный список.

        foreach (char c in new string(Path.GetInvalidFileNameChars()))
        {
            Console.Write((int)c);
            Console.Write(",");
        }

Вот простой Java-класс, который "очищает" имя файла.

public class FileNameCleaner {
final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};
static {
    Arrays.sort(illegalChars);
}
public static String cleanFileName(String badFileName) {
    StringBuilder cleanName = new StringBuilder();
    for (int i = 0; i < badFileName.length(); i++) {
        int c = (int)badFileName.charAt(i);
        if (Arrays.binarySearch(illegalChars, c) < 0) {
            cleanName.append((char)c);
        }
    }
    return cleanName.toString();
}
}

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

Следующий ответ содержит пример кода для создания настраиваемого контекста безопасности в Java и последующего выполнения кода в этой "песочнице".

Как создать безопасную изолированную песочницу JEXL (скриптов)?

Ответ 2

или просто выполните следующее:

String filename = "A20/B22b#öA\\BC#Ä$%ld_ma.la.xps";
String sane = filename.replaceAll("[^a-zA-Z0-9\\._]+", "_");

Результат: A20_B22b_A_BC_ld_ma.la.xps

Пояснение:

[a-zA-Z0-9\\._] соответствует букве a-z нижний или верхний регистр, цифры, точки и символы подчеркивания

[^a-zA-Z0-9\\._] является обратным. то есть все символы, которые не соответствуют первому выражению

[^a-zA-Z0-9\\._]+ - это последовательность символов, которые не соответствуют первому выражению

Итак, каждая последовательность символов, которая не состоит из символов из a-z, 0-9 или. _ будет заменен.

Ответ 3

Это основано на принятом ответе Sarel Botha, который отлично работает до тех пор, пока вы не встретите никаких символов вне Базовый многоязычный план. Если вам нужна полная поддержка Unicode (а кто нет?), Используйте этот код, который безопасен в Unicode:

public class FileNameCleaner {
  final static int[] illegalChars = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47};

  static {
    Arrays.sort(illegalChars);
  }

  public static String cleanFileName(String badFileName) {
    StringBuilder cleanName = new StringBuilder();
    int len = badFileName.codePointCount(0, badFileName.length());
    for (int i=0; i<len; i++) {
      int c = badFileName.codePointAt(i);
      if (Arrays.binarySearch(illegalChars, c) < 0) {
        cleanName.appendCodePoint(c);
      }
    }
    return cleanName.toString();
  }
}

Ключевые изменения здесь:

  • Используйте codePointCount i.c.w. length вместо length
  • используйте codePointAt вместо charAt
  • используйте appendCodePoint вместо append
  • Не нужно бросать char в int s. На самом деле, вы никогда не должны иметь дело с char, поскольку они в основном нарушены для чего-либо вне BMP.

Ответ 4

Там довольно хорошее встроенное решение Java - Character.isXxx().

Попробуйте Character.isJavaIdentifierPart(c):

String name = "name.é[email protected]#$%^&*(){}][/=?+-_\\|;:`~!'\",<>";
StringBuilder filename = new StringBuilder();

for (char c : name.toCharArray()) {
  if (c=='.' || Character.isJavaIdentifierPart(c)) {
    filename.append(c);
  }
}

Результат: "name.é $_".

Ответ 5

Вот код, который я использую:

public static String sanitizeName( String name ) {
    if( null == name ) {
        return "";
    }

    if( SystemUtils.IS_OS_LINUX ) {
        return name.replaceAll( "/+", "" ).trim();
    }

    return name.replaceAll( "[\u0001-\u001f<>:\"/\\\\|?*\u007f]+", "" ).trim();
}

SystemUtils из Apache commons-lang3

Ответ 6

Это не ясно из вашего вопроса, но поскольку вы планируете принимать имена путей из веб-формы (?), вы, вероятно, должны блокировать попытки переименования определенных вещей; например "C:\Program Files". Это означает, что вам нужно канонировать пути, чтобы исключить ".". и "..", прежде чем делать проверки доступа.

Учитывая, что я не пытаюсь удалить незаконные символы. Вместо этого я буду использовать "новый файл (str).getCanonicalFile()" для создания канонических путей, затем проверьте, что они удовлетворяют вашим ограничениям на песочницу, и, наконец, используйте "File.exists()", "File.isFile()", и т.д., чтобы проверить, что источник и место назначения являются кошерными и не являются тем же файловым файлом. Я имел дело с незаконными символами, пытаясь выполнить операции и поймать исключения.

Ответ 7

Если вы хотите использовать больше, чем как [A-Za-z0-9], то проверьте MS Naming Conventions и не забудьте отфильтровать "... Символы, чьи целые представления находятся в диапазоне от 1 до 31,... "Как пример Аарона Дигуллы. Например, код Дэвида Карбони не будет достаточным для этих символов.

Ответ 8

Paths.get(...) выдает подробное исключение с позицией недопустимого символа.

public static String removeInvalidChars(final String fileName)
{
  try
  {
    Paths.get(fileName);
    return fileName;
  }
  catch (final InvalidPathException e)
  {
    if (e.getInput() != null && e.getInput().length() > 0 && e.getIndex() >= 0)
    {
      final StringBuilder stringBuilder = new StringBuilder(e.getInput());
      stringBuilder.deleteCharAt(e.getIndex());
      return removeInvalidChars(stringBuilder.toString());
    }
    throw e;
  }
}