Java: podzielenie nazwy pliku na podstawę i rozszerzenie

83

Czy jest lepszy sposób na uzyskanie nazwy i rozszerzenia pliku niż coś takiego

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);
Jason S.
źródło
7
Spójrz na commons-io FilenameUtils . Ma metody getBaseName(..)i getExtension(..).
Bozho
Dla jedynego rozszerzenia, patrz stackoverflow.com/questions/3571223/... .
Andy Thomas

Odpowiedzi:

168

Wiem, że inni wspominali String.split, ale tutaj jest wariant, który daje tylko dwa tokeny (podstawa i rozszerzenie):

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

Na przykład:

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

Plony:

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

Wyrażenie regularne nakazuje Javie podzielić na dowolny okres, po którym następuje dowolna liczba znaków bez kropek, po których następuje koniec danych wejściowych. Jest tylko jeden okres, który pasuje do tej definicji (a mianowicie ostatni okres).

Technicznie rzecz biorąc, mówiąc regeksyjnie, technika ta nazywana jest dodatnim wyprzedzeniem o zerowej szerokości .


BTW, jeśli chcesz podzielić ścieżkę i uzyskać pełną nazwę pliku, w tym między innymi rozszerzenie kropki, używając ścieżki z ukośnikami,

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

Na przykład:

    String dir = "/foo/bar/bam/boozled"; 
    String[] tokens = dir.split(".+?/(?=[^/]+$)");
    // [ "/foo/bar/bam/" "boozled" ] 
Adam Paynter
źródło
2
Nie mam pojęcia, dlaczego ludzie boją się uzależnień ;-)
Bozho
3
@Bozho: Zgadzam się, że biblioteki są lepszymi rozwiązaniami tego typu problemów. Pozwala innym osobom zajmować się konserwacją i myśleniem za Ciebie (dlatego zagłosowałem za Twoją odpowiedzią!). Może to zabrzmieć banalnie, ale jest część mnie, która zawsze się waha, kiedy rozważam włączenie biblioteki Apache, ponieważ w przeszłości cierpiałem „piekło JAR” z niektórymi z ich rzeczy (wiem, to trywialne).
Adam Paynter
4
@Bozho: Adam ma 100% racji. Ten problem nie wystarczyłby, abym wziął kolejną bibliotekę - ale gdybym już korzystał z commons-io z innych powodów, użyłbym Filenameutils.
Jason S
1
@Jason: Wyrażenia regularne: prezent, który ciągle daje. :)
Adam Paynter
3
@Bozho - Sarkazm? Prawdziwe pytanie brzmi, dlaczego java zawiera niekończące się stosy zbędnych klas, które są tak bliskie ułatwienia robienia tego, co chcesz, ale frustrujące nigdy tego nie robią. Nie ma odpowiednika Apache-Commons w Pythonie, ponieważ Python po prostu ma już wbudowane wszystkie przydatne rzeczy, które chcesz. C # wydaje się być kolejnym przykładem języka, w którym można skupić się na swoim wyjątkowym problemie, zamiast zastanawiać się, jak na nowo wynaleźć koło lub zdobyć koło wymyślone przez kogoś innego.
ArtOfWarfare
84

Stare pytanie, ale zwykle używam tego rozwiązania:

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" !)
Oibaf to
źródło
Nie działa, jeśli pracujesz w systemie Windows, a ciąg „nazwa_pliku” to „D: \ resources \ ftp_upload.csv” Czy możesz pomóc?
NIKHIL CHAURASIA
3
@NIKHILCHAURASIA musisz uciec przed ukośnikami, podwajając je. Na przykład: „D: \\ resources \\ ftp_upload.csv”.
Ricket
8

Źródło: http://www.java2s.com/Code/Java/File-Input-Output/Getextensionpathandfilename.htm

taka klasa użyteczności:

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);
  }
}

stosowanie:

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());
  }
}
Erhan Bagdemir
źródło
4
basename()byłoby lepszą nazwą zamiastfilename()
nimcap
w przypadku braku rozszerzenia (np. nazwa pliku, taka jak „/ etc / hosts”), zwróci to „hosts” jako rozszerzenie (zamiast „”). Klasy użytkowe klasy bibliotecznej powinny zajmować się przypadkami narożnymi.
Zach-M
6

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

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

Java ma wbudowane funkcje, aby uzyskać podstawową nazwę i nazwę katalogu dla danej ścieżki pliku, ale nazwy funkcji nie są tak oczywiste.

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());
    }
}

źródło
5
java.io.File.getName () zwraca nazwę z rozszerzeniem.
Bram
2
Wolę myśleć, że nie ma czegoś takiego jak „rozszerzenie” :-)
4

Rozszerzenia plików to zepsuta koncepcja

I nie istnieje żadnej niezawodne działanie dla niego. Rozważmy na przykład tę nazwę pliku:

archive.tar.gz

Co to jest rozszerzenie? Użytkownicy DOS woleliby tę nazwę archive.tgz. Czasami widzisz głupie aplikacje Windows, które najpierw dekompresują plik (dając .tarplik), a następnie musisz go ponownie otworzyć, aby zobaczyć zawartość archiwum.

W takim przypadku bardziej rozsądne byłoby pojęcie rozszerzenia pliku .tar.gz. Istnieje również .tar.bz2, .tar.xz, .tar.lza .tar.lzmaplik „Rozszerzenia” w użyciu. Ale jak zdecydowałbyś, czy podzielić na ostatnią kropkę, czy przedostatnią kropkę?

Zamiast tego użyj typów MIME.

Funkcja Files.probeContentType języka Java 7 będzie prawdopodobnie znacznie bardziej niezawodna w wykrywaniu typów plików niż ufanie rozszerzeniu pliku. Prawie cały świat Unix / Linux, a także Twoja przeglądarka internetowa i smartfon już to robią.

Has QUIT - Anony-Mousse
źródło
6
Jak to odpowiada na pytanie? Ani Filenie Pathpozwól mi oddzielić rozszerzenia.
Andreas Abel
@ andreas.abel pozwolę sobie powtórzyć: rozszerzenia plików to zepsuta koncepcja. Nie są one wiarygodne ani dobrze zdefiniowane, z wyjątkiem nazw plików w systemie DOS 8 + 3 (rozważ w .tar.gzporównaniu z .tgzzbyt powszechnymi na unixach). Zamiast tego użyj typów MIME.
WYJŚCIE - Anony-Mousse
1
@ Anony-Mousse Cóż, w zasadzie się zgadzam, ale 99,999% wszystkich systemów, z którymi współpracuję, używa nazwy pliku, a nie typu mime
Christian Sauer
Gdzie jest problem w używaniu Files.probeContentType zamiast polegania na nazwie pliku, aby mieć właściwe rozszerzenie?
WYJŚCIE - Anony-Mousse
3
To nie odpowiada na pytanie. Mam przypadek użycia, w którym nazwa pliku, film, to nazwa + rozszerzenie. Jak wyodrębnić nazwę przy użyciu typów MIME?
Niek
1

Co jest nie tak z twoim kodem? Zapakowany w zgrabną metodę użytkową jest w porządku.

Ważniejsze jest to, czego użyć jako separatora - pierwszej lub ostatniej kropki. Pierwszy jest zły dla nazw plików, takich jak „setup-2.5.1.exe”, a ostatni jest zły dla nazw plików z wieloma rozszerzeniami, na przykład „mybundle.tar.gz”.

Mot
źródło
-3

Może mógłbyś użyć String # split

Aby odpowiedzieć na Twój komentarz:

Nie jestem pewien, czy może być więcej niż jeden. w nazwie pliku, ale cokolwiek, nawet jeśli jest więcej kropek, możesz użyć podziału. Weź pod uwagę np., Że:

String input = "boo.and.foo";

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

To zwróci tablicę zawierającą:

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

Będziesz więc wiedział, że ostatni indeks w tablicy jest rozszerzeniem, a wszystkie inne są podstawą.


źródło
cóż, tak, ale musiałbym znaleźć wyrażenie regularne dla ostatniego .w ciągu
Jason S,
1
Hmm nie jestem pewien, ale nie możesz po prostu użyć „.”? A może nazwa pliku zawiera więcej niż 1 kropkę?
2
Myślę, że to zadziała:fileName.split("\\.(?=[^\\.]+$)")
Adam Paynter
1
Nie możesz zakładać, że jest tylko jedna kropka. Adam: dzięki, spróbuję.
Jason S
4
Ta odpowiedź jest nieprawidłowa. Ponieważ kropka nie została zmieniona, zwróci pustą tablicę.
aled