Java: разделение имени файла на основание и расширение

83

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

File f = ...
String name = f.getName();
int dot = name.lastIndexOf('.');
String base = (dot == -1) ? name : name.substring(0, dot);
String extension = (dot == -1) ? "" : name.substring(dot+1);
Джейсон С
источник
7
Взгляните на commons-io FilenameUtils . Она имеет getBaseName(..)и getExtension(..)методы.
Божо
Для только расширения, см stackoverflow.com/questions/3571223/... .
Энди Томас

Ответы:

168

Я знаю, что другие упоминали String.split, но вот вариант, который дает только два токена (базовый и расширенный):

String[] tokens = fileName.split("\\.(?=[^\\.]+$)");

Например:

"test.cool.awesome.txt".split("\\.(?=[^\\.]+$)");

Урожайность:

["test.cool.awesome", "txt"]

Регулярное выражение указывает Java разбить на любой период, за которым следует любое количество непериодов, за которым следует конец ввода. Этому определению соответствует только один период (а именно, последний период).

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


Кстати, если вы хотите разделить путь и получить полное имя файла, включая, помимо прочего, расширение точки, используя путь с косой чертой,

    String[] tokens = dir.split(".+?/(?=[^/]+$)");

Например:

    String dir = "/foo/bar/bam/boozled"; 
    String[] tokens = dir.split(".+?/(?=[^/]+$)");
    // [ "/foo/bar/bam/" "boozled" ] 
Адам Пэйнтер
источник
2
Понятия не имею, почему люди боятся зависимостей ;-)
Божо
3
@Bozho: Я согласен с тем, что библиотеки - лучшее решение для такого типа проблем. Это позволяет другим людям поддерживать вас и думать за вас (поэтому я поддержал ваш ответ!). Это может показаться тривиальным, но есть часть меня, которая всегда сомневается, когда я рассматриваю возможность включения библиотеки Apache, потому что в прошлом я перенес "ад JAR" с некоторыми из их материалов (я знаю, это тривиально).
Адам Пэйнтер
4
@Bozho: Адам на 100% прав. Этой проблемы было бы недостаточно, чтобы гарантировать, что я займусь еще одной библиотекой, но если бы я уже использовал commons-io по другим причинам, я бы использовал Filenameutils.
Jason S
1
@Jason: Регулярные выражения: подарок, который не перестает дарить. :)
Adam Paynter
3
@Bozho - Сарказм? Настоящий вопрос заключается в том, почему java поставляется с бесконечным количеством избыточных классов, которые настолько близки к тому, чтобы упростить выполнение того, что вы действительно хотите сделать, но при этом, к сожалению, никогда этого не делают. В Python нет эквивалента Apache-Commons, потому что в Python уже есть все полезные вещи, которые вы хотите встроить. C # кажется еще одним примером языка, в котором вы можете сосредоточиться на своей уникальной проблеме вместо того, чтобы выяснять, как заново изобрести колесо или взять колесо, изобретенное кем-то другим.
ArtOfWarfare
84

Старый вопрос, но я обычно использую это решение:

import org.apache.commons.io.FilenameUtils;

String fileName = "/abc/defg/file.txt";

String basename = FilenameUtils.getBaseName(fileName);
String extension = FilenameUtils.getExtension(fileName);
System.out.println(basename); // file
System.out.println(extension); // txt (NOT ".txt" !)
Ойбаф это
источник
Не работает, если работает в Windows, а строка "fileName" - "D: \ resources \ ftp_upload.csv". Не могли бы вы помочь?
NIKHIL CHAURASIA
3
@NIKHILCHAURASIA, вам нужно избежать обратных косых черт, удвоив их. Например: "D: \\ resources \\ ftp_upload.csv".
Ricket
8

Источник: http://www.java2s.com/Code/Java/File-Input-Output/Getextensionpathandfilename.htm

такой служебный класс:

class Filename {
  private String fullPath;
  private char pathSeparator, extensionSeparator;

  public Filename(String str, char sep, char ext) {
    fullPath = str;
    pathSeparator = sep;
    extensionSeparator = ext;
  }

  public String extension() {
    int dot = fullPath.lastIndexOf(extensionSeparator);
    return fullPath.substring(dot + 1);
  }

  public String filename() { // gets filename without extension
    int dot = fullPath.lastIndexOf(extensionSeparator);
    int sep = fullPath.lastIndexOf(pathSeparator);
    return fullPath.substring(sep + 1, dot);
  }

  public String path() {
    int sep = fullPath.lastIndexOf(pathSeparator);
    return fullPath.substring(0, sep);
  }
}

Применение:

public class FilenameDemo {
  public static void main(String[] args) {
    final String FPATH = "/home/mem/index.html";
    Filename myHomePage = new Filename(FPATH, '/', '.');
    System.out.println("Extension = " + myHomePage.extension());
    System.out.println("Filename = " + myHomePage.filename());
    System.out.println("Path = " + myHomePage.path());
  }
}
Эрхан Багдемир
источник
4
basename()было бы лучше вместоfilename()
nimcap
в случае отсутствия расширения (например, имени файла, такого как «/ etc / hosts»), в качестве расширения будет возвращено «hosts» (а не «»). Служебные классы библиотечного уровня должны позаботиться о крайних случаях.
Zach-M
6

http://docs.oracle.com/javase/6/docs/api/java/io/File.html#getName ()

С http://www.xinotes.org/notes/note/774/ :

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

import java.io.File;

public class JavaFileDirNameBaseName {
    public static void main(String[] args) {
    File theFile = new File("../foo/bar/baz.txt");
    System.out.println("Dirname: " + theFile.getParent());
    System.out.println("Basename: " + theFile.getName());
    }
}

источник
5
java.io.File.getName () возвращает имя с расширением.
Bram
2
Я предпочитаю думать, что не существует такого понятия, как «расширение» :-)
4

Расширения файлов - это сломанная концепция

И не существует нет надежной функции для него. Рассмотрим, например, это имя файла:

archive.tar.gz

Что такое расширение? Пользователи DOS предпочли бы это имя archive.tgz. Иногда вы видите глупые приложения Windows, которые сначала распаковывают файл (что дает.tar файл), а затем вам нужно снова открыть его, чтобы увидеть содержимое архива.

В этом случае более разумным понятием расширения файла было бы .tar.gz . Есть также .tar.bz2, .tar.xz, .tar.lzи .tar.lzmaфайл «расширения» в использовании. Но как бы вы решили, разделять ли последнюю точку или предпоследнюю точку?

Вместо этого используйте mime-типы.

Функция Java 7 Files.probeContentType , вероятно, будет намного надежнее определять типы файлов, чем доверять расширению файла. Практически весь мир Unix / Linux, а также ваш веб-браузер и смартфон уже делают это таким образом.

ВЫЙТИ - Anony-Mousse
источник
6
Как это отвечает на вопрос? Ни, Fileни Pathпозвольте мне отщепить расширение.
Андреас Абель
@ andreas.abel, позвольте мне повторить: расширения файлов - это сломанная концепция. Они не являются надежными, ни четко определенной за исключением имен файлов DOS 8 + 3 (рассмотрим .tar.gzпротив .tgzслишком часто встречается на UNIX). Вместо этого используйте типы пантомимы.
ВЫЙТИ - Anony-Mousse
1
@ Anony-Mousse Что ж, я согласен в принципе, но 99,999% всех систем, с
Кристиан Зауэр
В чем проблема использования Files.probeContentTypeимени файла вместо того, чтобы полагаться на правильное расширение?
ВЫЙТИ - Anony-Mousse
3
Это не отвечает на вопрос. У меня есть вариант использования, когда имя файла, фильм, является именем + расширением. Как мне извлечь имя с помощью mime-типов?
Niek
1

Что не так с вашим кодом? Обернутый аккуратной утилитой, все в порядке.

Важнее то, что использовать в качестве разделителя - первую или последнюю точку. Первый плохо подходит для имен файлов, таких как «setup-2.5.1.exe», последний - для имен файлов с несколькими расширениями, таких как «mybundle.tar.gz».

Mot
источник
-3

Возможно, вы могли бы использовать String # split

Чтобы ответить на ваш комментарий:

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

String input = "boo.and.foo";

String[] result = input.split(".");

Это вернет массив, содержащий:

{ "boo", "and", "foo" }

Таким образом, вы будете знать, что последний индекс в массиве - это расширение, а все остальные - базовый.


источник
ну да, но мне нужно было бы вычислить регулярное выражение для последнего .в строке
Джейсон С.
1
Хм, я не уверен, но нельзя ли просто использовать "."? Или в имени файла больше 1 точки?
2
Думаю, это сработает:fileName.split("\\.(?=[^\\.]+$)")
Адам Пейнтер
1
Вы не можете предположить, что есть только одна точка. Адам: спасибо, попробую.
Jason S
4
Это неверный ответ. Поскольку точка не экранирована, она вернет пустой массив.
Эль