Почему Java автоматически декодирует% 2F в именах файлов в кодировке URI? - PullRequest
6 голосов
/ 04 мая 2010

У меня есть сервлет, который должен записывать файлы с настраиваемым пользователем именем. Я пытаюсь использовать кодировку URI для правильного экранирования специальных символов, но JRE, по-видимому, автоматически преобразовывает закодированные прямые косые черты %2F в разделители пути.

Пример:

File   dir = new File("C:\Documents and Setting\username\temp");
String fn  = "Top 1/2.pdf";
URI    uri = new URI( dir.toURI().toASCIIString() + URLEncoder.encoder( fn, "ASCII" ).toString() );
File   out = new File( uri );

System.out.println( dir.toURI().toASCIIString() );
System.out.println( URLEncoder.encode( fn, "ASCII" ).toString() );
System.out.println( uri.toASCIIString() );
System.out.println( output.toURI().toASCIIString() );

Вывод:

file:/C:/Documents%20and%20Settings/username/temp/
Top+1%2F2.pdf   
file:/C:/Documents%20and%20Settings/username/temp/Top+1%2F2.pdf
file:/C:/Documents%20and%20Settings/username/temp/Top+1/2.pdf

После создания нового объекта File последовательность %2F автоматически преобразуется в косую черту, и я получаю неправильный путь. Кто-нибудь знает правильный подход к этой проблеме?

Суть проблемы заключается в том, что

uri.equals( new File(uri).toURI() ) == FALSE

когда в URI есть %2F.

Я планирую просто использовать дословно закодированную строку URLE, а не пытаться использовать конструктор File(uri).

Ответы [ 2 ]

5 голосов
/ 04 мая 2010

new File(URI) создает файл на основе пути, полученного с помощью URI#getPath() вместо того, что вы ожидали - URI#getRawPath(). Это похоже на функцию «по замыслу».

У вас есть 2 варианта:

  1. Выполнить URLEncoder#encode() на fn дважды (примечание: encode(), а не encoder()).
  2. Вместо этого используйте new File(String).
2 голосов
/ 04 мая 2010

Я думаю, что @BalusC прибил прямую проблему в вашем коде. Я просто хотел бы указать на некоторые другие вопросы

Выражения dir.toURI().toASCIIString() и URLEncoder.encoder(fn, "UTF-8").toString() на самом деле делают довольно разные вещи.

  • Первый кодирует URI в виде строки, применяя правила кодирования URI в соответствии с грамматикой URI. Так, например, «/» в компоненте пути не будет кодироваться, а «/» в компоненте запроса или фрагмента будет кодироваться как% 2F.

  • Второй кодирует строку fn, применяющую правила кодирования без ссылки на содержимое строки.

Отображение конструктора File(URI) из URI файла в файл зависит от системы и недокументировано . Я немного удивлен, что он декодирует %2F, но он делает то, что делает, и @BalusC объясняет почему. Вывод заключается в том, что потенциально проблематично использовать механизм («file:» URI), который явно зависит от системы.

Наконец, неправильно комбинировать эти строки компонентов URI таким образом. Это должно быть либо

URI uri = new URI(
        dir.toURI().toString() +
        URLEncoder.encoder(fn, "UTF-8").toString();

или

URI uri = new URI(
        dir.toURI().toASCIIString() +
        URLEncoder.encoder(fn, "ASCII").toString());
...