1. 概要

このチュートリアルでは、Java を使用して、特定の文字列にOSの有効なファイル名があるかどうかを検証するさまざまな方法について説明します。 制限された文字または長さの制限に対して値を確認したいと思います。

例を通して、外部の依存関係を使用せずに、コアソリューションに焦点を当てます。 SDKのjava.io およびNIO2パッケージを確認し、最終的に独自のソリューションを実装します。

2. java.io.Fileを使用する

java .io.Fileクラスを使用して、最初の例から始めましょう。 このソリューションでは、指定された文字列を使用して File インスタンスを作成してから、ローカルディスクにファイルを作成する必要があります。

public static boolean validateStringFilenameUsingIO(String filename) throws IOException {
    File file = new File(filename);
    boolean created = false;
    try {
        created = file.createNewFile();
        return created;
    } finally {
        if (created) {
            file.delete();
        }
    }
}

指定されたファイル名が正しくない場合、はIOExceptionをスローします。内部でファイルが作成されるため、このメソッドでは、指定されたファイル名 Stringが正しくないことに注意してください。 tは既存のファイルに対応します。

さまざまなファイルシステムには、独自のファイル名の制限があることがわかっています。 したがって、 java .io.File メソッドを使用すると、Javaが自動的に処理するため、OSごとにルールを指定する必要はありません。

ただし、ダミーファイルを作成する必要があります。 成功したら、最後に削除することを忘れないでください。 さらに、これらのアクションを実行するための適切な権限があることを確認する必要があります。 障害が発生するとIOExceptionも発生する可能性があるため、エラーメッセージを確認することをお勧めします。

// Windows invalid filename
assertThatThrownBy(() -> validateStringFilenameUsingIO("baeldung?.txt"))
  .isInstanceOf(IOException.class)
  .hasMessageContaining("Invalid file path");

3. NIO2APIの使用

ご存知のとおり、 java.io パッケージには、Javaの最初のバージョンで作成されたため、多くの欠点があります。 java.ioパッケージの後継であるNIO2APIは多くの改善をもたらし、これにより以前のソリューションも大幅に簡素化されます。

public static boolean validateStringFilenameUsingNIO2(String filename) {
    Paths.get(filename);
    return true;
}

私たちの機能は合理化されたので、そのようなテストを実行するための最速の方法です。 ファイルを作成しないので、はディスク権限を持っている必要はなく、テスト後にクリーニングを実行します。

無効なファイル名は、 InvalidPathException、をスローします。これはRuntimeExceptionを拡張します。 エラーメッセージには、前のメッセージよりも多くの詳細も含まれています。

// Windows invalid filename
assertThatThrownBy(() -> validateStringFilenameUsingNIO2(filename))
  .isInstanceOf(InvalidPathException.class)
  .hasMessageContaining("character not allowed");

このソリューションには、ファイルシステムの制限に関連する1つの重大な欠点があります。 Path クラスは、サブディレクトリを持つファイルパスを表す場合があります。 最初の例とは異なり、このメソッドはファイル名文字のオーバーフロー制限をチェックしません。 ApacheCommonsのrandomAlphabetic()メソッドを使用して生成された500文字のランダムなStringと照合してみましょう。

String filename = RandomStringUtils.randomAlphabetic(500);
assertThatThrownBy(() -> validateStringFilenameUsingIO(filename))
  .isInstanceOf(IOException.class)
  .hasMessageContaining("File name too long");

assertThat(validateStringFilenameUsingNIO2(filename)).isTrue();

これを修正するには、以前と同様に、ファイルを作成して結果を確認する必要があります。

4.4。 カスタム実装

最後に、ファイル名をテストするための独自のカスタム関数を実装してみましょう。 また、I / O機能を回避し、コアJavaメソッドのみを使用するようにします。

これらの種類のソリューションは、より詳細な制御を提供し、独自のルールを実装できるようにします。 ただし、さまざまなシステムの多くの追加の制限を考慮する必要があります。

4.1. String.containsを使用する

String.contains()メソッドを使用して、指定されたStringが禁止文字のいずれかを保持しているかどうかを確認できます。 まず、いくつかの値の例を手動で指定する必要があります。

public static final Character[] INVALID_WINDOWS_SPECIFIC_CHARS = {'"', '*', ':', '<', '>', '?', '\\', '|', 0x7F};
public static final Character[] INVALID_UNIX_SPECIFIC_CHARS = {'\000'};

この例では、これら2つのOSのみに焦点を当てましょう。 ご存知のとおり、Windowsのファイル名はUNIXよりも制限されています。 また、一部の空白文字は問題がある可能性があります

制限された文字セットを定義した後、現在のOSを決定しましょう。

public static Character[] getInvalidCharsByOS() {
    String os = System.getProperty("os.name").toLowerCase();
    if (os.contains("win")) {
        return INVALID_WINDOWS_SPECIFIC_CHARS;
    } else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) {
        return INVALID_UNIX_SPECIFIC_CHARS;
    } else {
        return new Character[]{};
    }
}

そして今、私たちはそれを使って与えられた値をテストすることができます:

public static boolean validateStringFilenameUsingContains(String filename) {
    if (filename == null || filename.isEmpty() || filename.length() > 255) {
        return false;
    }
    return Arrays.stream(getInvalidCharsByOS())
      .noneMatch(ch -> filename.contains(ch.toString()));
}

このStream述語は、定義された文字のいずれかが指定されたファイル名にない場合にtrueを返します。 さらに、null値と誤った長さのサポートを実装しました。

4.2. 正規表現パターンマッチング

また、は、指定されたStringに対して正規表現を直接使用することもできます。 長さが255以下の英数字とドット文字のみを受け入れるパターンを実装してみましょう。

public static final String REGEX_PATTERN = "^[A-za-z0-9.]{1,255}$";

public static boolean validateStringFilenameUsingRegex(String filename) {
    if (filename == null) {
        return false;
    }
    return filename.matches(REGEX_PATTERN);
}

これで、前に準備したパターンに対して指定された値をテストできます。 パターンを簡単に変更することもできます。 この例では、OSチェック機能をスキップしました。

5. 結論

この記事では、ファイル名とその制限に焦点を当てました。 Javaを使用して無効なファイル名を検出するためのさまざまなアルゴリズムを導入しました。

java.io パッケージから始めました。これは、がシステム制限のほとんどを処理しますが、追加のI / Oアクションを実行し、いくつかの権限が必要になる場合があります。 次に、が最速のソリューションであるNIO2 APIをチェックしましたが、ファイル名の長さのチェック制限があります。

最後に、I / O APIを使用せずに独自のメソッドを実装しましたが、ファイルシステムルールのカスタム実装が必要です。

GitHub で、追加のテストを使用したすべての例を見つけることができます。