1. 概要

Javaでファイルを操作する場合、ファイル名を処理する必要があることがよくあります。 たとえば、特定のファイル名から拡張子なしの名前を取得したい場合があります。 つまり、ファイル名の拡張子を削除したいのです。

このチュートリアルでは、ファイル名から拡張子を削除する一般的な方法について説明します。

2. ファイル名から拡張子を削除するシナリオ

最初に見てみると、ファイル名から拡張子を削除するのは非常に簡単な問題だと思うかもしれません。

ただし、問題を詳しく見ると、思ったよりも複雑になる可能性があります。

まず、ファイル名の種類を見てみましょう。

  • 拡張子なし、たとえば「baeldung」
  • 単一の拡張子の場合、これは最も一般的なケースです。たとえば、「baeldung.txt
  • baeldung.tar.gz」のような複数の拡張子
  • .baeldung」などの拡張子のないドットファイル
  • 単一の拡張子を持つDotfile、たとえば「.baeldung.conf
  • 複数の拡張子を持つDotfile、たとえば「.baeldung.conf.bak

次に、拡張機能を削除した後の上記の例の期待される結果をリストします。

  • baeldung」:ファイル名に拡張子がありません。 したがって、ファイル名は変更しないでください。「baeldung」を取得する必要があります。
  • baeldung.txt」:これは単純なケースです。 正しい結果は「baeldung」です。
  • baeldung.tar.gz」:このファイル名には2つの拡張子が含まれています。 1つの拡張子のみを削除する場合は、「baeldung.tar」が結果になります。 ただし、ファイル名からすべての拡張子を削除する場合は、「baeldung」が正しい結果になります。
  • .baeldung」:このファイル名にも拡張子がないため、ファイル名も変更しないでください。 したがって、結果には「.baeldung」が表示されると予想されます。
  • .baeldung.conf」:結果は「.baeldung」になります。
  • .baeldung.conf.bak」:拡張子を1つだけ削除する場合、結果は「.baeldung.conf」になります。 それ以外の場合、すべての拡張機能を削除すると、「.baeldung」が期待される出力になります

このチュートリアルでは、GuavaおよびApacheCommonsIOによって提供されるユーティリティメソッドが上記のすべてのケースを処理できるかどうかをテストします。

さらに、特定のファイル名から拡張子(または複数の拡張子)を削除する問題を解決する一般的な方法についても説明します。

3. グアバライブラリのテスト

バージョン14.0以降、 GuavaFiles.getNameWithoutExtension()メソッドを導入しました。 これにより、指定したファイル名から拡張子を簡単に削除できます。

ユーティリティメソッドを使用するには、Guavaライブラリをクラスパスに追加する必要があります。 たとえば、ビルドツールとしてMavenを使用する場合、Guava依存関係pom.xmlファイルに追加できます。

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

まず、このメソッドの実装を見てみましょう。

public static String getNameWithoutExtension(String file) {
   ...
   int dotIndex = fileName.lastIndexOf('.');
   return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
 }

実装は非常に簡単です。 ファイル名にドットが含まれている場合、メソッドはファイル名の最後のドットから末尾までを切り取ります。 それ以外の場合、ファイル名にドットが含まれていない場合は、元のファイル名が変更されずに返されます。

したがって、 GuavaのgetNameWithoutExtension()メソッドは、拡張子のないドットファイルでは機能しません。 それを証明するテストを書いてみましょう:

@Test
public void givenDotFileWithoutExt_whenCallGuavaMethod_thenCannotGetDesiredResult() {
    //negative assertion
    assertNotEquals(".baeldung", Files.getNameWithoutExtension(".baeldung"));
}

複数の拡張子を持つファイル名を処理する場合、このメソッドは、ファイル名からすべての拡張子を削除するオプションを提供しません:

@Test
public void givenFileWithoutMultipleExt_whenCallGuavaMethod_thenCannotRemoveAllExtensions() {
    //negative assertion
    assertNotEquals("baeldung", Files.getNameWithoutExtension("baeldung.tar.gz"));
}

4. ApacheCommonsIOライブラリのテスト

Guavaライブラリと同様に、人気のある Apache Commons IO ライブラリは、 FilenameUtilsクラスにremoveExtension()メソッドを提供し、ファイル名の拡張子をすばやく削除します。

このメソッドを見る前に、 ApacheCommonsIO依存関係pom.xmlに追加しましょう。

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.8.0</version>
</dependency>

実装は、Guavaの getNameWithoutExtension()メソッドに似ています。

public static String removeExtension(final String filename) {
    ...
    final int index = indexOfExtension(filename); //used the String.lastIndexOf() method
    if (index == NOT_FOUND) {
  	return filename;
    } else {
	return filename.substring(0, index);
    }
}

したがって、 ApacheCommonsIOのメソッドはdotfilesでも機能しません。

@Test
public void givenDotFileWithoutExt_whenCallApacheCommonsMethod_thenCannotGetDesiredResult() {
    //negative assertion
    assertNotEquals(".baeldung", FilenameUtils.removeExtension(".baeldung"));
}

ファイル名に複数の拡張子がある場合、 removeExtension()メソッドはすべての拡張子を削除できません。

@Test
public void givenFileWithoutMultipleExt_whenCallApacheCommonsMethod_thenCannotRemoveAllExtensions() {
    //negative assertion
    assertNotEquals("baeldung", FilenameUtils.removeExtension("baeldung.tar.gz"));
}

5. ファイル名からの拡張子の削除

これまで、広く使用されている2つのライブラリのファイル名から拡張子を削除するためのユーティリティメソッドを見てきました。 どちらの方法も非常に便利で、最も一般的なケースで機能します。

ただし、一方で、いくつかの欠点があります。

  • たとえば、「.baeldung」などのドットファイルでは機能しません。
  • ファイル名に複数の拡張子がある場合、最後の拡張子のみまたはすべての拡張子を削除するオプションは提供されません

次に、すべてのケースをカバーするメソッドを作成しましょう。

public static String removeFileExtension(String filename, boolean removeAllExtensions) {
    if (filename == null || filename.isEmpty()) {
        return filename;
    }

    String extPattern = "(?<!^)[.]" + (removeAllExtensions ? ".*" : "[^.]*$");
    return filename.replaceAll(extPattern, "");
}

booleanパラメーターremoveAllExtensionsを追加して、ファイル名からすべての拡張子または最後の拡張子のみを削除するオプションを提供しました。

このメソッドのコア部分は、regexパターンです。 それでは、このregexパターンが何をするのかを理解しましょう。

  • 「(? <!^)[.]” –私たちはネガティブルックビハインドこれで正規表現 。 ファイル名の先頭にないドット「」と一致します
  • 「「 (? <!^)[.].* 」– removeAllExtensions オプションが設定されている場合、これはファイル名の最後まで最初に一致したドットと一致します
  • 「「 (? <!^)[.][^.]*$ 」–このパターンは最後の拡張子にのみ一致します

最後に、いくつかのテストメソッドを記述して、このメソッドがすべての異なるケースで機能するかどうかを確認しましょう。

@Test
public void givenFilenameNoExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {
    assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung", true));
    assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung", false));
}

@Test
public void givenSingleExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {
    assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung.txt", true));
    assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung.txt", false));
}

@Test
public void givenDotFile_whenCallFilenameUtilMethod_thenGetExpectedFilename() {
    assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung", true));
    assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung", false));
}

@Test
public void givenDotFileWithExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {
    assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung.conf", true));
    assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung.conf", false));
}

@Test
public void givenDoubleExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {
    assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung.tar.gz", true));
    assertEquals("baeldung.tar", MyFilenameUtil.removeFileExtension("baeldung.tar.gz", false));
}

@Test
public void givenDotFileWithDoubleExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {
    assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung.conf.bak", true));
    assertEquals(".baeldung.conf", MyFilenameUtil.removeFileExtension(".baeldung.conf.bak", false));
}

6. 結論

この記事では、特定のファイル名から拡張子を削除する方法について説明しました。

最初に、拡張機能を削除するさまざまなシナリオについて説明しました。

次に、広く使用されている2つのライブラリであるGuavaとApacheCommonsIOが提供するメソッドを紹介します。 これらは非常に便利で、一般的なケースでは機能しますが、ドットファイルでは機能しません。 また、単一の拡張機能またはすべての拡張機能を削除するオプションはありません。

最後に、すべての要件をカバーするメソッドを構築しました。

いつものように、記事の完全なソースコードは、GitHubから入手できます。