1. ホーム
  2. java

[解決済み] Javaで文字列を安全にエンコードしてファイル名として使用するにはどうすればよいですか?

2022-06-15 15:06:40

質問

外部プロセスから文字列を受信しています。私はその文字列を使用してファイル名を作成し、そのファイルに書き込むことを望んでいます。これを行うための私のコードスニペットは次のとおりです。

    String s = ... // comes from external source
    File currentFile = new File(System.getProperty("user.home"), s);
    PrintWriter currentWriter = new PrintWriter(currentFile);

s が Unix 系 OS の '/' のような無効な文字を含む場合、java.io.FileNotFoundException が(正しく)スローされます。

ファイル名として使用できるように文字列を安全にエンコードするにはどうしたらよいでしょうか。

編集:私が望んでいるのは、これをやってくれるAPIコールです。

私はこれをすることができます。

    String s = ... // comes from external source
    File currentFile = new File(System.getProperty("user.home"), URLEncoder.encode(s, "UTF-8"));
    PrintWriter currentWriter = new PrintWriter(currentFile);

しかし、私はURLEncoderがこの目的のために信頼できるかどうかわからない。

どのように解決するのですか?

元のファイルと同じような結果を得たい場合、SHA-1 やその他のハッシュ方式では解決できません。 衝突を避けなければならない場合、単純な置換や悪い文字の除去も解決策にはなりません。

代わりに、次のようなものが必要です。 (注意: これは説明のための例として扱われるべきで、コピー アンド ペーストするためのものではありません)。

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

この解決策は可逆的なエンコーディング(衝突がない)をもたらし、エンコードされた文字列はほとんどの場合、元の文字列に類似しています。 私はあなたが8ビット文字を使用していると仮定しています。

URLEncoder は動作しますが、合法的なファイル名文字全体をエンコードしてしまうという欠点があります。

可逆性が保証されない解決策を望むなら、エスケープ シーケンスで置き換えるのではなく、単に「悪い」文字を削除してください。


上記のエンコーディングの逆も同様に簡単に実装できるはずです。