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: Регулярні вирази: подарунок, який продовжує дарувати. :)
Адам Пейнтер,

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" !)

Не працює, якщо робота у вікнах і для рядка "fileName" вказано "D: \ resources \ ftp_upload.csv" Чи можете ви допомогти?
НІХІЛ ЧАУРАЗІЯ

3
@NIKHILCHAURASIA вам потрібно уникнути зворотних скісних рисок, подвоївши їх. Наприклад: "D: \\ ресурси \\ 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 () повертає ім'я з розширенням.
Брем

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, а також ваш веб-браузер та смартфон вже роблять це таким чином.


6
Як це відповідає на питання? І Fileне Pathдозвольте мені розділити розширення.
Андреас Абель

@ andreas.abel дозвольте мені повторити це: Розширення файлів - нерозвинене поняття. Вони не є надійними та чітко визначеними, за винятком імен файлів DOS 8 + 3 (враховуйте .tar.gzпорівняно з .tgzнадто поширеними в unix). Замість цього використовуйте типи mime.
Вийшов - Аноні-Мус

1
@ Anony-Mousse Ну, я принципово погоджуюсь, але 99,999% усіх систем, з якими я взаємодію, використовують ім'я файлу, а не тип mime
Крістіан Зауер,

Де проблема у використанні Files.probeContentTypeзамість того, щоб покладатися на ім’я файлу, щоб мати правильне розширення?
ВИХІД - Аноні-Мус

3
Це не відповідає на питання. У мене є варіант використання, коли ім'я файлу, фільм, є ім'ям і розширенням. Як витягти назву за допомогою mime-типів?
Niek

1

Що не так із вашим кодом? Опакований акуратним корисним методом - це добре.

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



-3

Може, ти міг би використати String # split

Щоб відповісти на ваш коментар:

Я не впевнений, чи може бути більше одного. в назві файлу, але незалежно від того, навіть якщо є більше точок, ви можете використовувати розділення. Подумайте, наприклад, що:

String input = "boo.and.foo";

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

Це поверне масив, що містить:

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

Отже, ви будете знати, що останній індекс масиву - це розширення, а всі інші - основа.


ну так, але я повинен був би зрозуміти регулярний вираз для останнього .в рядку
Jason S

1
Хм, я не впевнений, але не можеш просто використати "."? Або більше 1 крапки в назві файлу?

2
Я думаю, це могло б спрацювати:fileName.split("\\.(?=[^\\.]+$)")
Адам Пейнтер

1
Ви не можете припустити, що є лише одна крапка. Адам: дякую, я спробую.
Jason S

4
Ця відповідь неправильна. Оскільки крапка не захищена, вона поверне порожній масив.
Олег
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.