Как я могу безопасно закодировать строку в Java для использования в качестве имени файла?

Это не могло бы рассчитать как "книга разработки", но я должен добавить ее так или иначе: Хакеры Stephen Levy. Я нашел, что это говорило с эмоциональной стороной программирования.

105
задан Steve McLeod 26 July 2009 в 10:30
поделиться

4 ответа

If you want the result to resemble the original file, SHA-1 or any other hashing scheme is not the answer. If collisions must be avoided, then simple replacement or removal of "bad" characters is not the answer either.

Instead you want something like this.

char fileSep = '/'; // ... or do this portably.
char escape = '%'; // ... or some other legal char.
String s = ...
int len = s.length();
StringBuilder sb = new StringBuilder(len);
for (int i = 0; i < len; i++) {
    char ch = s.charAt(i);
    if (ch < ' ' || ch >= 0x7F || ch == fileSep || ... // add other illegal chars
        || (ch == '.' && i == 0) // we don't want to collide with "." or ".."!
        || ch == escape) {
        sb.append(escape);
        if (ch < 0x10) {
            sb.append('0');
        }
        sb.append(Integer.toHexString(ch));
    } else {
        sb.append(ch);
    }
}
File currentFile = new File(System.getProperty("user.home"), sb.toString());
PrintWriter currentWriter = new PrintWriter(currentFile);

This solution gives a reversible encoding (with no collisions) where the encoded strings resemble the original strings in most cases. I'm assuming that you are using 8-bit characters.

URLEncoder works, but it has the disadvantage that it encodes a whole lot of legal file name characters.

If you want a not-guaranteed-to-be-reversible solution, then simply remove the 'bad' characters rather than replacing them with escape sequences.

14
ответ дан 24 November 2019 в 03:59
поделиться

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

String name = s.replaceAll("\\W+", "");

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

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

По этой причине я обычно позволяю пользователю вводить то, что он хочет, сохранять имя файла на основе схемы по моему собственному выбору (например, userId_fileId ), а затем сохраните имя файла пользователя в таблице базы данных. Таким образом, вы можете отображать его обратно пользователю, хранить вещи так, как вы хотите, и не подвергать риску безопасность и не стирать другие файлы.

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

РЕДАКТИРОВАТЬ: Исправлено регулярное выражение для java

98
ответ дан 24 November 2019 в 03:59
поделиться

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

Обратимая

Используйте кодировку URL ( java.net.URLEncoder ) для замены специальных символов на % xx . Обратите внимание, что вы учитываете особые случаи , где строка равна . , равно .. или пусто! ¹ Многие программы используют кодировку URL-адресов для создания имен файлов, поэтому это стандартный метод, понятный всем.

Необратимый

Используйте хэш (например, SHA-1) данной строки. Современные алгоритмы хеширования ( не MD5) можно считать бесконфликтными. Фактически, у вас будет прорыв в криптографии, если вы обнаружите коллизию.


¹ Вы можете элегантно обработать все 3 особых случая, используя такой префикс, как «myApp -» . Если вы поместите файл прямо в $ HOME , вам все равно придется это сделать, чтобы избежать конфликтов с существующими файлами, такими как ".bashrc".
public static String encodeFilename(String s)
{
    try
    {
        return "myApp-" + java.net.URLEncoder.encode(s, "UTF-8");
    }
    catch (java.io.UnsupportedEncodingException e)
    {
        throw new RuntimeException("UTF-8 is an unknown encoding!?");
    }
}
34
ответ дан 24 November 2019 в 03:59
поделиться

Вы можете удалить недопустимые символы ('/', '\', '?', '*'), А затем использовать их.

0
ответ дан 24 November 2019 в 03:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: