Рубрики
Без рубрики

Получить имя файла без расширения в Java

Изучите различные способы удаления расширения из имени файла

Автор оригинала: Kai Yuan.

1. Обзор

Когда мы работаем с файлами на Java, нам часто приходится обрабатывать имена файлов. Например, иногда мы хотим получить имя без расширения из данного имени файла. Другими словами, мы хотим удалить расширение имени файла.

В этом уроке мы обсудим общий способ удаления расширения из имени файла.

2. Сценарии удаления расширения Из имени файла

Когда мы впервые взглянем на него, мы можем подумать, что удаление расширения из имени файла-довольно простая проблема.

Однако, если мы рассмотрим проблему более внимательно, она может оказаться более сложной, чем мы думали.

Прежде всего, давайте посмотрим на типы файлов, которые могут быть:

  • Без какого-либо расширения, например, ” baeldung”
  • С одним расширением это самый обычный случай, например, ” baeldung.txt
  • С несколькими расширениями, такими как ” baeldung.tar.gz
  • Точечный файл без расширения, например ” .baeldung
  • Точечный файл с одним расширением, например, ” .baeldung.conf
  • Точечный файл с несколькими расширениями, например,” . baeldung.conf.bak

Далее мы перечислим результаты приведенных выше примеров после удаления расширения(ов):

  • baeldung “: Имя файла не имеет расширения. Поэтому имя файла не должно быть изменено, и мы должны получить ” baeldung
  • baeldung.txt “: Это простой случай. Правильный результат ” baeldung
  • baeldung.tar.gz “: Это имя файла содержит два расширения. Если мы хотим удалить только одно расширение, результатом должно быть ” baeldung.tar “. Но если мы хотим удалить все расширения из имени файла, ” baeldung ” является правильным результатом
  • .baeldung “: Поскольку это имя файла также не имеет расширения, имя файла также не должно быть изменено. Таким образом, мы ожидаем увидеть ” .baeldung ” в результате
  • .baeldung.conf “: Результат должен быть ” .baeldung
  • .baeldung.conf.bak “: Результатом должно быть “.baeldung.conf”, если мы хотим удалить только одно расширение. В противном случае, ” .baeldung ” является ожидаемым результатом, если мы удалим все расширения

В этом уроке мы проверим, могут ли служебные методы, предоставляемые Guava и Apache Commons IO, обрабатывать все случаи, перечисленные выше.

Кроме того, мы также обсудим общий способ решения проблемы удаления расширения (или расширений) из данного имени файла.

3. Тестирование библиотеки Гуавы

Начиная с версии 14.0, Guava ввел метод Files.getNameWithoutExtension () . Это позволяет нам легко удалить расширение из данного имени файла.

Чтобы использовать метод утилиты, нам нужно добавить библиотеку Guava в ваш путь к классам. Например, если мы используем Maven в качестве инструмента сборки, мы можем добавить зависимость Guava в ваш pom.xml файл:


    com.google.guava
    guava
    30.0-jre

Во – первых, давайте рассмотрим реализацию этого метода:

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

Реализация довольно проста. Если имя файла содержит точки, метод сокращает путь от последней точки до конца имени файла. В противном случае, если имя файла не содержит точки, исходное имя файла будет возвращено без каких-либо изменений.

Поэтому метод Guava getNameWithoutExtension() не будет работать для dotfiles без расширения. Давайте напишем тест, чтобы доказать, что:

@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. Тестирование библиотеки ввода-вывода Apache Commons

Как и библиотека Guava, популярная библиотека Apache Commons IO предоставляет метод remove Extension() в классе FilenameUtils для быстрого удаления расширения имени файла.

Прежде чем мы рассмотрим этот метод, давайте добавим зависимость Apache Commons IO в ваш pom.xml :


    commons-io
    commons-io
    2.8.0

Реализация аналогична методу 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);
    }
}

Поэтому метод Apache Commons IO также не будет работать с dotfiles :

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

Если имя файла имеет несколько расширений, удалить расширение() метод не может удалить все расширения:

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

5. Удаление расширений Из имени файла

До сих пор мы видели утилиты для удаления расширения из имени файла в двух широко используемых библиотеках. Оба метода довольно удобны и работают по наиболее распространенным причинам.

Однако, с другой стороны, у них есть некоторые недостатки:

  • Они не будут работать для dotfiles, например, ” .baeldung
  • Если имя файла имеет несколько расширений, они не предоставляют возможность удалить только последнее расширение или все расширения

Далее, давайте построим метод, чтобы охватить все случаи:

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

    String extPattern = "(?

Мы добавили логический параметр удалить все расширения , чтобы предоставить возможность удалить все расширения или только последнее расширение из имени файла.

Основной частью этого метода является шаблон regex . Итак, давайте разберемся, что делает этот регулярное выражение шаблон:

  • “(? – Мы используем negative-lookbehind в этом регулярном выражении . Он соответствует точке” . “, которая не находится в начале имени файла
  • – Мы используем negative-lookbehind в этом регулярном выражении . Он соответствует точке”
  • . “, которая не находится в начале имени файла

Наконец, давайте напишем несколько методов тестирования, чтобы проверить, работает ли наш метод для всех разных случаев:

@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. Заключение

В этой статье мы говорили о том, как удалить расширения из данного имени файла.

Во-первых, мы обсудили различные сценарии удаления расширений.

Далее мы представили методы, предоставляемые двумя широко используемыми библиотеками: Guava и Apache Commons IO. Они довольно удобны и работают для обычных случаев, но не могут работать для dotfiles. Кроме того, они не предоставляют возможность удалить одно расширение или все расширения.

Наконец, мы разработали метод, который удовлетворяет всем требованиям.

Как всегда, полный исходный код статьи доступен на GitHub .