64

オンラインで取得したデータに基づいてファイルの名前を変更するクロスプラットフォーム アプリケーションを作成しています。現在のプラットフォームの Web API から取得した文字列をサニタイズしたいと考えています。

プラットフォームごとにファイル名の要件が異なることを知っているので、これを行うクロスプラットフォームの方法があるかどうか疑問に思っていましたか?

編集: Windows プラットフォームでは、疑問符「?」を使用できません。をファイル名で使用できますが、Linux では可能です。ファイル名にはそのような文字が含まれている可能性があり、これらの文字をサポートするプラットフォームでそれらを保持したいと思いますが、そうでない場合は削除してください。

また、サードパーティのライブラリを必要としない標準の Java ソリューションを好むでしょう。

4

8 に答える 8

31

他の場所で提案されているように、これは通常、やりたいことではありません。通常は、File.createTempFile() などの安全な方法を使用して一時ファイルを作成することをお勧めします。

ホワイトリストでこれを行うべきではなく、「良い」文字のみを保持してください。ファイルが中国語のみで構成されている場合は、すべてを削除します。このため、ホワイトリストを使用することはできません。ブラックリストを使用する必要があります。

Linux では、本当に面倒なことは何でも許されます。Linux を Windows を制限するのと同じリストに制限するだけで、将来の頭痛の種を避けることができます。

Windows でこの C# スニペットを使用して、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();
}
}

編集:スティーブンが示唆したように、これらのファイルアクセスが許可したディレクトリ内でのみ発生することも確認する必要があります。

次の回答には、Java でカスタム セキュリティ コンテキストを確立し、その「サンドボックス」でコードを実行するためのサンプル コードがあります。

安全な JEXL (スクリプト) サンドボックスを作成するにはどうすればよいですか?

于 2011-04-11T19:18:54.887 に答える
27

またはこれを行う:

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\\._]+最初の式に一致しない一連の文字です

したがって、az、0-9、または . _が置き換えられます。

于 2013-07-19T11:37:05.693 に答える
8

私が使用するコードは次のとおりです。

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

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

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

SystemUtilsApache commons-lang3からのものです

于 2014-07-11T07:53:59.603 に答える
6

Character.isXxx()というかなり優れた組み込み Java ソリューションがあります。

試してくださいCharacter.isJavaIdentifierPart(c)

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

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

結果は「name.é$_」です。

于 2012-11-08T16:33:46.147 に答える
5

あなたの質問からは明らかではありませんが、Web フォーム (?) からパス名を受け入れることを計画しているので、おそらく特定のものの名前を変更する試みをブロックする必要があります。例: "C:\Program Files"。これは、「.」を除去するためにパス名を正規化する必要があることを意味します。アクセス チェックを行う前に、「..」と「..」を使用します。

それを考えると、私は違法な文字を削除しようとはしません. 代わりに、「new File(str).getCanonicalFile()」を使用して標準パスを生成し、次にそれらがサンドボックスの制限を満たしていることを確認し、最後に「File.exists()」、「File.isFile()」を使用します。などを使用して、ソースと宛先がコーシャであり、同じファイル システム オブジェクトではないことを確認します。操作を試みて例外をキャッチすることで、不正な文字に対処します。

于 2009-07-20T23:11:44.040 に答える