Як отримати розширення файлу на Java?


484

Щоб було зрозуміло, я не шукаю типу MIME.

Скажімо, у мене є такий вклад: /path/to/file/foo.txt

Я хотів би розбити цей вклад, зокрема, .txtдля розширення. Чи є вбудований спосіб зробити це на Java? Я хотів би уникати написання власного аналізатора.


12
Ви ніколи не знаєте, коли збирається якась нова платформа, яка визначає розширення як розділені комою. Тепер потрібно написати залежний від платформи код. Каркаси Java повинні бути більш перспективними і мати API для отримання розширень, де вони пишуть код залежно від платформи, і ви, як користувач API, просто скажете отримати розширення.
ArtOfWarfare

@ArtOfWarfare: OMG. Давайте створимо 100 МБ JRE з багатьма тисячами класів, але будь ласка, не забудьте не застосовувати жодного методу, який повертається "txt"з-за того, "filename.txt"що десь платформа десь може захотіти використовувати "filename,txt".
Ерік Думініл

@EricDuminil "Обов'язково не застосовуйте жодного методу, який повертає" txt "з" filename.txt "" ??? Спробуйте path.substring(path.lastIndexOf("."));..... І так .. Вони впевнені, що не дублюють щось дарма ...
VelocityPulse

@VelocityPulse Це саме те , що мене турбує. Оскільки немає стандартного способу отримати розширення файлу, ви отримуєте десятки напівправильних відповідей та трохи інші реалізації. Ваш код використовує 2 способи (я хотів би мати один єдиний, явний метод), він повертається ".txt"з "filename.txt", що може бути не бажаним результатом, і найгірше, що він не спрацьовує, StringIndexOutOfBoundsExceptionа не повертає порожню рядок, якщо немає розширення.
Ерік Думініл

Відповіді:


649

У цьому випадку використовуйте FilenameUtils.getExtension з IO Apache Commons

Ось приклад, як його використовувати (ви можете вказати або повний шлях, або просто ім'я файлу):

String ext1 = FilenameUtils.getExtension("/path/to/file/foo.txt"); // returns "txt"
String ext2 = FilenameUtils.getExtension("bar.exe"); // returns "exe"

Залежна залежність:

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

Gradle Groovy DSL

implementation 'commons-io:commons-io:2.6'

Gradle Kotlin DSL

implementation("commons-io:commons-io:2.6")

Інші https://search.maven.org/artifact/commons-io/commons-io/2.6/jar


70
Слід зазначити, що він повертає лише "gz" для файлу з іменем archive.tar.gz.
Zitrax

106
@Zitrax тому, що "gz" - це розширення файлу.
BrainSlugs83,

6
@ BrainSlugs83 Отже, що означає "дьоготь"?
TuGordoBello

31
@zhelon .gz означає gnu zipped file, а .tar означає (t) ape (ar) цибулю. Отже .tar.gz - це файл tar у внутрішньому файлі gnu, який має розширення .gz.
cirovladimir

5
Немає підстав залучати до іншої бібліотеки для цього простого завдання.
masterwok

311

Вам справді потрібен «парсер» для цього?

String extension = "";

int i = fileName.lastIndexOf('.');
if (i > 0) {
    extension = fileName.substring(i+1);
}

Якщо припустити, що ви маєте справу з простими іменами файлів, схожих на Windows, а не з подібними archive.tar.gz.

Btw, для випадку, якщо в каталозі може бути ".", Але саме ім'я файлу не (як /path/to.a/file), ви можете зробити

String extension = "";

int i = fileName.lastIndexOf('.');
int p = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));

if (i > p) {
    extension = fileName.substring(i+1);
}

4
Дякую! Звичайно, вам може знадобитися аналізатор / об'єкт, якщо ви хочете зробити більше маніпуляцій, ніж просто розширення ... скажіть, якщо ви хочете лише шлях, батьківський каталог, ім'я файлу (мінус розширення) тощо. I ' м родом із C # і .Net, де у нас це: msdn.microsoft.com/en-us/library/…
longda

10
Як ви кажете, є кілька речей, про які варто задуматися, крім простого використання наївного lastIndexOf ("."). Я б здогадався, що Apache Commons має метод для цього, який враховує всі маленькі хитрі потенційні проблеми.
MatrixFrog

12
Я думаю, що i > 0слід змінити на i >= 0або i != -1. Це піклується про такі назви файлів, як .htaccess.
Pijusn

8
незалежно від того, наскільки простий будь-який фрагмент коду ... вам все одно потрібно оновити / підтримувати його / протестувати / зробити його доступним як зручну залежність ... набагато простіше, якщо вже є ліб, що все це робить
Дон Чедл

2
На більше gotcha - це якщо файл закінчується крапкою. Краще в лібці. if (i> p && i <(fileName.length () - 1)) {extension = fileName.substring (i + 1);
tgkprog

97
private String getFileExtension(File file) {
    String name = file.getName();
    int lastIndexOf = name.lastIndexOf(".");
    if (lastIndexOf == -1) {
        return ""; // empty extension
    }
    return name.substring(lastIndexOf);
}

13
Слід зазначити, що це повертає значення '.' також розширення файлу буде ".txt" на відміну від "txt" в деяких інших відповідях
NickEntin

2
Краща відповідь та @NickEntin Кращий коментар. Щоб видалити період ". з розширення файлу, може бути закодовано як int lastIndexOf = name.lastIndexOf (".") + 1;
Ханзалла Афган

11
такий підхід може не працювати в деяких випадках, наприклад, /usr/bin/foo.bar/httpconf
Іман Акбарі

8
@ lukasz1985 1. сотні пакетів Linux складають каталоги з такими іменами, як "init.d", крім того, не безпечно покладатися на шлях, що не має каталогів з крапками, оскільки це не є незаконним. 2. Я кодував Android, тому використовував деякий SDK метод я не пам’ятаю, але, мабуть, у stackoverflow.com/a/3571239/2546146 немає цього недоліку
Іман Акбарі

6
@Iman Akbari: getName () повертає лише саме ім'я файлу, яке було б у вашому прикладі "httpconf".
Президент Dreamspace

85

Якщо ви користуєтеся бібліотекою Guava , ви можете вдатися до Filesкорисного класу. Він має метод , специфічний, getFileExtension(). Наприклад:

String path = "c:/path/to/file/foo.txt";
String ext = Files.getFileExtension(path);
System.out.println(ext); //prints txt

Крім того, ви також можете отримати ім'я файлу з подібною функцією, getNameWithoutExtension () :

String filename = Files.getNameWithoutExtension(path);
System.out.println(filename); //prints foo

4
Дійсно? Це чудова бібліотека, повна утиліт. Більшість з них буде частиною Java8, як і чудова функція Guava .
JeanValjean

На жаль, не всі люди можуть вирішити, якими бібліотеками користуватися, на жаль. Принаймні, у нас є Apache Commons, хоч і стара.
Lluis Martinez

1
якщо ви бачите вихідний код getFileExtensionнасправді, це просто int dotIndex = fileName.lastIndexOf('.'); return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1)не велика справа. також зауважте, що Filesз певних причин позначено як "нестабільне".
Аль-Мотафар

@ Al-Mothafar дуже багато класів позначені як нестабільні (див. Мультимапа будівельників), я також не розумію, чому: кілька звільнених зроблено, але нічого там не змінилося.
JeanValjean

27

Якщо на Android ви можете скористатися цим:

String ext = android.webkit.MimeTypeMap.getFileExtensionFromUrl(file.getName());

Зауважте, що це не буде працювати, якщо рядок не кодується (наприклад, містить пробіл чи китайський символ), див.: Stackoverflow.com/a/14321470/1074998
Fruit

14

Для того, щоб врахувати імена файлів без символів перед крапкою, вам потрібно використовувати незначну зміну прийнятої відповіді:

String extension = "";

int i = fileName.lastIndexOf('.');
if (i >= 0) {
    extension = fileName.substring(i+1);
}

"file.doc" => "doc"
"file.doc.gz" => "gz"
".doc" => "doc"

напевно, слід захищати себе від "foo". вхід.
chrisinmtown

14

Це перевірений метод

public static String getExtension(String fileName) {
    char ch;
    int len;
    if(fileName==null || 
            (len = fileName.length())==0 || 
            (ch = fileName.charAt(len-1))=='/' || ch=='\\' || //in the case of a directory
             ch=='.' ) //in the case of . or ..
        return "";
    int dotInd = fileName.lastIndexOf('.'),
        sepInd = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
    if( dotInd<=sepInd )
        return "";
    else
        return fileName.substring(dotInd+1).toLowerCase();
}

І тестовий випадок:

@Test
public void testGetExtension() {
    assertEquals("", getExtension("C"));
    assertEquals("ext", getExtension("C.ext"));
    assertEquals("ext", getExtension("A/B/C.ext"));
    assertEquals("", getExtension("A/B/C.ext/"));
    assertEquals("", getExtension("A/B/C.ext/.."));
    assertEquals("bin", getExtension("A/B/C.bin"));
    assertEquals("hidden", getExtension(".hidden"));
    assertEquals("dsstore", getExtension("/user/home/.dsstore"));
    assertEquals("", getExtension(".strange."));
    assertEquals("3", getExtension("1.2.3"));
    assertEquals("exe", getExtension("C:\\Program Files (x86)\\java\\bin\\javaw.exe"));
}

10

Моя брудна і може бути найменшою за допомогою String.replaceAll :

.replaceAll("^.*\\.(.*)$", "$1")

Зауважте, що спочатку *жадібний, тому він захопить більшість можливих символів наскільки це можливо, а потім залишиться лише остання крапка та розширення файлу.


Це не вдається, якщо файл не має розширення.
Зак

Так, на жаль, все ж можна використовувати для простих сценаріїв, таких як швидке виявлення типу файлів, і, наприклад, неправильне розширення, не дуже відрізняється від відсутності, або можна поставити умову if, коли результат заміни дорівнює вводу.
Ебрагім Бягові

1
Або ще коротше.replaceAll(".*\\.", "")
Ебрагім Бягові

10
String path = "/Users/test/test.txt";
String extension = "";

if (path.contains("."))
     extension = path.substring(path.lastIndexOf("."));

повернути ".txt"

якщо ви хочете лише "txt", зробіть path.lastIndexOf(".") + 1


9

Як очевидно з усіх інших відповідей, немає адекватної "вбудованої" функції. Це безпечний і простий метод.

String getFileExtension(File file) {
    if (file == null) {
        return "";
    }
    String name = file.getName();
    int i = name.lastIndexOf('.');
    String ext = i > 0 ? name.substring(i + 1) : "";
    return ext;
}


6

Якщо ви плануєте використовувати Apache commons-io і просто хочете перевірити розширення файлу, а потім виконати деяку операцію, ви можете скористатися цим , ось фрагмент:

if(FilenameUtils.isExtension(file.getName(),"java")) {
    someoperation();
}

Зауважте, що ця перевірка відрізняється від регістру відповідно до документів.
Бабкен Варданян

6

Ось ще один одноклапник для Java 8.

String ext = Arrays.stream(fileName.split("\\.")).reduce((a,b) -> b).orElse(null)

Він працює наступним чином:

  1. Розбийте рядок на масив рядків, використовуючи "."
  2. Перетворити масив у потік
  3. Використовуйте зменшити, щоб отримати останній елемент потоку, тобто розширення файлу

4

Як щодо JFileChooser? Це не просто, оскільки вам потрібно буде проаналізувати його кінцевий результат ...

JFileChooser filechooser = new JFileChooser();
File file = new File("your.txt");
System.out.println("the extension type:"+filechooser.getTypeDescription(file));

що тип MIME ...

Гаразд ... Я забуваю, що ви не хочете знати його тип MIME.

Цікавий код за наступним посиланням: http://download.oracle.com/javase/tutorial/uiswing/components/filechooser.html

/*
 * Get the extension of a file.
 */  
public static String getExtension(File f) {
    String ext = null;
    String s = f.getName();
    int i = s.lastIndexOf('.');

    if (i > 0 &&  i < s.length() - 1) {
        ext = s.substring(i+1).toLowerCase();
    }
    return ext;
}

Пов'язане запитання: Як обрізати розширення файлу з рядка на Java?


4

Ось метод, який .tar.gzправильно поводиться , навіть у шляху з крапками в іменах каталогу:

private static final String getExtension(final String filename) {
  if (filename == null) return null;
  final String afterLastSlash = filename.substring(filename.lastIndexOf('/') + 1);
  final int afterLastBackslash = afterLastSlash.lastIndexOf('\\') + 1;
  final int dotIndex = afterLastSlash.indexOf('.', afterLastBackslash);
  return (dotIndex == -1) ? "" : afterLastSlash.substring(dotIndex + 1);
}

afterLastSlashстворено для afterLastBackslashшвидшого пошуку, оскільки не доведеться шукати весь рядок, якщо в ньому є косої риски.

char[]В оригіналі Stringвикористовується повторно, не додаючи сміття там, і віртуальна машина, ймовірно , помітили , що afterLastSlashвідразу ж сміття для того , щоб помістити його в стек замість купи .


цей метод скопійовано з вихідного коду Guava, про це потрібно згадати.
гумав

1
Я цього не копіював. Якщо він знаходиться у вихідному коді Guava, вони скопіювали його звідси. Можливо, сповістіть їх.
Олате

Вибачте за те, що це не однакове btw, тому, можливо, у вас і у розробника Guava просто одна і та ж думка.
гумав

2
Дійсно "gz" - це правильне розширення для повернення. Якщо викликовий код також може працювати з "дьогтем", то він повинен додатково перевірити, що знаходиться поза getExtensionфункцією. Якщо ім'я файлу користувача є, "my zip. don't touch.tar.gz"то цей метод поверне неправильне розширення.
intrepidis

2
// Modified from EboMike's answer

String extension = "/path/to/file/foo.txt".substring("/path/to/file/foo.txt".lastIndexOf('.'));

Розширення повинно містити ".txt" під час запуску.


13
Збій, якщо в імені немає розширення.
EboMike

2

Ось версія з необов’язковим як зворотним значенням (тому що ви не можете бути впевнені, що файл має розширення) ... також перевірки правильності ...

import java.io.File;
import java.util.Optional;

public class GetFileExtensionTool {

    public static Optional<String> getFileExtension(File file) {
        if (file == null) {
            throw new NullPointerException("file argument was null");
        }
        if (!file.isFile()) {
            throw new IllegalArgumentException("getFileExtension(File file)"
                    + " called on File object that wasn't an actual file"
                    + " (perhaps a directory or device?). file had path: "
                    + file.getAbsolutePath());
        }
        String fileName = file.getName();
        int i = fileName.lastIndexOf('.');
        if (i > 0) {
            return Optional.of(fileName.substring(i + 1));
        } else {
            return Optional.empty();
        }
    }
}

2

Як щодо версії REGEX :

static final Pattern PATTERN = Pattern.compile("(.*)\\.(.*)");

Matcher m = PATTERN.matcher(path);
if (m.find()) {
    System.out.println("File path/name: " + m.group(1));
    System.out.println("Extention: " + m.group(2));
}

або з підтримкою нульового розширення:

static final Pattern PATTERN =
    Pattern.compile("((.*\\" + File.separator + ")?(.*)(\\.(.*)))|(.*\\" + File.separator + ")?(.*)");

class Separated {
    String path, name, ext;
}

Separated parsePath(String path) {
    Separated res = new Separated();
    Matcher m = PATTERN.matcher(path);
    if (m.find()) {
        if (m.group(1) != null) {
            res.path = m.group(2);
            res.name = m.group(3);
            res.ext = m.group(5);
        } else {
            res.path = m.group(6);
            res.name = m.group(7);
        }
    }
    return res;
}


Separated sp = parsePath("/root/docs/readme.txt");
System.out.println("path: " + sp.path);
System.out.println("name: " + sp.name);
System.out.println("Extention: " + sp.ext);

результат для * nix:
path: / root / docs /
name: readme
Розширення: txt

для windows, parsePath ("c: \ windows \ readme.txt"):
path: c: \ windows \
name: readme
Розширення: txt



1

Тут я зробив невеликий метод (однак не такий безпечний і не перевіряє наявність багатьох помилок), але якщо програмувати загальну java-програму лише ви, цього більш ніж достатньо, щоб знайти тип файлу. Це не працює для складних типів файлів, але вони зазвичай не використовуються так сильно.

    public static String getFileType(String path){
       String fileType = null;
       fileType = path.substring(path.indexOf('.',path.lastIndexOf('/'))+1).toUpperCase();
       return fileType;
}

ОП шукає вбудований метод
Panther

(1) Ви повинні використовувати lastIndexOfтак, щоб назви файлів, як-от john.smith.report.doc, поводилися належним чином. (2) Ви повинні належним чином обробляти випадки, коли розширення не існує. Цей метод повертає ABC/XYZтакий шлях abc/xyz, який не має сенсу. Було б більше сенсу повернутися ""або null. (3) Розділювач файлів не завжди /.
Radiodef

1

Отримання розширення файлу від імені файлу

/**
 * The extension separator character.
 */
private static final char EXTENSION_SEPARATOR = '.';

/**
 * The Unix separator character.
 */
private static final char UNIX_SEPARATOR = '/';

/**
 * The Windows separator character.
 */
private static final char WINDOWS_SEPARATOR = '\\';

/**
 * The system separator character.
 */
private static final char SYSTEM_SEPARATOR = File.separatorChar;

/**
 * Gets the extension of a filename.
 * <p>
 * This method returns the textual part of the filename after the last dot.
 * There must be no directory separator after the dot.
 * <pre>
 * foo.txt      --> "txt"
 * a/b/c.jpg    --> "jpg"
 * a/b.txt/c    --> ""
 * a/b/c        --> ""
 * </pre>
 * <p>
 * The output will be the same irrespective of the machine that the code is running on.
 *
 * @param filename the filename to retrieve the extension of.
 * @return the extension of the file or an empty string if none exists.
 */
public static String getExtension(String filename) {
    if (filename == null) {
        return null;
    }
    int index = indexOfExtension(filename);
    if (index == -1) {
        return "";
    } else {
        return filename.substring(index + 1);
    }
}

/**
 * Returns the index of the last extension separator character, which is a dot.
 * <p>
 * This method also checks that there is no directory separator after the last dot.
 * To do this it uses {@link #indexOfLastSeparator(String)} which will
 * handle a file in either Unix or Windows format.
 * <p>
 * The output will be the same irrespective of the machine that the code is running on.
 *
 * @param filename  the filename to find the last path separator in, null returns -1
 * @return the index of the last separator character, or -1 if there
 * is no such character
 */
public static int indexOfExtension(String filename) {
    if (filename == null) {
        return -1;
    }
    int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
    int lastSeparator = indexOfLastSeparator(filename);
    return (lastSeparator > extensionPos ? -1 : extensionPos);
}

/**
 * Returns the index of the last directory separator character.
 * <p>
 * This method will handle a file in either Unix or Windows format.
 * The position of the last forward or backslash is returned.
 * <p>
 * The output will be the same irrespective of the machine that the code is running on.
 *
 * @param filename  the filename to find the last path separator in, null returns -1
 * @return the index of the last separator character, or -1 if there
 * is no such character
 */
public static int indexOfLastSeparator(String filename) {
    if (filename == null) {
        return -1;
    }
    int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
    int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
    return Math.max(lastUnixPos, lastWindowsPos);
}

Кредити

  1. Скопійовано з класу Apache FileNameUtils - http://grepcode.com/file/repo1.maven.org/maven2/commons-io/commons-io/1.3.2/org/apache/commons/io/FilenameUtils.java#FilenameUtils. getExtension% 28java.lang.String% 29

1

Без використання будь-якої бібліотеки ви можете використовувати метод String, розділений так:

        String[] splits = fileNames.get(i).split("\\.");

        String extension = "";

        if(splits.length >= 2)
        {
            extension = splits[splits.length-1];
        }

0

Просто альтернатива на основі регулярних виразів. Не так швидко, не так добре.

Pattern pattern = Pattern.compile("\\.([^.]*)$");
Matcher matcher = pattern.matcher(fileName);

if (matcher.find()) {
    String ext = matcher.group(1);
}

0

Я знайшов кращий спосіб знайти розширення, змішавши всі відповіді вище

public static String getFileExtension(String fileLink) {

        String extension;
        Uri uri = Uri.parse(fileLink);
        String scheme = uri.getScheme();
        if (scheme != null && scheme.equals(ContentResolver.SCHEME_CONTENT)) {
            MimeTypeMap mime = MimeTypeMap.getSingleton();
            extension = mime.getExtensionFromMimeType(CoreApp.getInstance().getContentResolver().getType(uri));
        } else {
            extension = MimeTypeMap.getFileExtensionFromUrl(fileLink);
        }

        return extension;
    }

public static String getMimeType(String fileLink) {
        String type = CoreApp.getInstance().getContentResolver().getType(Uri.parse(fileLink));
        if (!TextUtils.isEmpty(type)) return type;
        MimeTypeMap mime = MimeTypeMap.getSingleton();
        return mime.getMimeTypeFromExtension(FileChooserUtil.getFileExtension(fileLink));
    }

0

Мені подобається простота відповіді спектра , і в одному з його коментарів є посилання на іншу відповідь, яка фіксує крапки в файлових шляхах, на інше питання, зроблене EboMike .

Не застосовуючи якийсь сторонній API, я пропоную:

private String getFileExtension(File file) {

    String name = file.getName().substring(Math.max(file.getName().lastIndexOf('/'),
            file.getName().lastIndexOf('\\')) < 0 ? 0 : Math.max(file.getName().lastIndexOf('/'),
            file.getName().lastIndexOf('\\')));
    int lastIndexOf = name.lastIndexOf(".");
    if (lastIndexOf == -1) {
        return ""; // empty extension
    }
    return name.substring(lastIndexOf + 1); // doesn't return "." with extension
}

Щось подібне може бути корисним у, скажімо, будь-якому з writeметодів ImageIO , де потрібно передати формат файлу.

Навіщо використовувати цілий API API, коли ви можете робити сам?


0

Цей конкретний питання доставив мені багато проблем, тоді я знайшов дуже просте рішення цієї проблеми, яку я розміщую тут.

file.getName().toLowerCase().endsWith(".txt");

Це воно.


3
ОП потребує способу отримання розширення - не тестувати його.
Предраг Манойлович

насправді все, що ви розробляєте, в більшості випадків вам потрібно мати справу лише з певним типом файлів. Тому, якщо ваша проблема виникає в цій області, це допоможе вам.
Vikram Bhardwaj

4
Що не відповідає його вимогам
Предраг Манойлович

2
Це не відповідь на питання, але це було саме те, що я шукав.
Едіолот

-1

спробуйте це.

String[] extension = "adadad.adad.adnandad.jpg".split("\\.(?=[^\\.]+$)"); // ['adadad.adad.adnandad','jpg']
extension[1] // jpg

-1
  @Test
    public void getFileExtension(String fileName){
      String extension = null;
      List<String> list = new ArrayList<>();
      do{
          extension =  FilenameUtils.getExtension(fileName);
          if(extension==null){
              break;
          }
          if(!extension.isEmpty()){
              list.add("."+extension);
          }
          fileName = FilenameUtils.getBaseName(fileName);
      }while (!extension.isEmpty());
      Collections.reverse(list);
      System.out.println(list.toString());
    }

-4

У Java є вбудований спосіб вирішення цього питання в класі java.nio.file.Files , який може працювати для ваших потреб:

File f = new File("/path/to/file/foo.txt");
String ext = Files.probeContentType(f.toPath());
if(ext.equalsIgnoreCase("txt")) do whatever;

Зауважте, що цей статичний метод використовує технічні характеристики, знайдені тут, для отримання "типу вмісту", який може змінюватися.


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