Java: Aufteilen des Dateinamens in eine Basis und eine Erweiterung

83

Gibt es einen besseren Weg, um den Basisnamen und die Dateierweiterung einer Datei zu erhalten als so etwas

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.
quelle
7
Schauen Sie sich commons-io an FilenameUtils . Es hat die getBaseName(..)und getExtension(..)Methoden.
Bozho
Für nur die Erweiterung finden stackoverflow.com/questions/3571223/... .
Andy Thomas

Antworten:

168

Ich weiß, dass andere erwähnt haben String.split, aber hier ist eine Variante, die nur zwei Token (die Basis und die Erweiterung) ergibt :

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

Zum Beispiel:

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

Ausbeuten:

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

Der reguläre Ausdruck weist Java an, sich auf einen Zeitraum aufzuteilen, auf den eine beliebige Anzahl von Nicht-Zeiträumen folgt, gefolgt vom Ende der Eingabe. Es gibt nur einen Zeitraum, der dieser Definition entspricht (nämlich den letzten Zeitraum).

Technisch Regexisch gesehen wird diese Technik als positiver Lookahead mit der Breite Null bezeichnet .


Übrigens, wenn Sie einen Pfad teilen und den vollständigen Dateinamen einschließlich, aber nicht beschränkt auf die Punktverlängerung erhalten möchten, indem Sie einen Pfad mit Schrägstrichen verwenden,

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

Zum Beispiel:

    String dir = "/foo/bar/bam/boozled"; 
    String[] tokens = dir.split(".+?/(?=[^/]+$)");
    // [ "/foo/bar/bam/" "boozled" ] 
Adam Paynter
quelle
2
Ich habe keine Ahnung, warum Menschen Angst vor Abhängigkeiten haben ;-)
Bozho
3
@Bozho: Ich stimme zu, dass Bibliotheken bessere Lösungen für diese Art von Problem sind. Es ermöglicht anderen Menschen, für Sie zu warten und nachzudenken (deshalb habe ich Ihre Antwort positiv bewertet!). Das mag trivial klingen, aber es gibt einen Teil von mir, der immer zögert, wenn ich überlege, eine Apache-Bibliothek aufzunehmen, weil ich in der Vergangenheit mit einigen ihrer Sachen unter der "JAR-Hölle" gelitten habe (ich weiß, es ist trivial).
Adam Paynter
4
@Bozho: Adam hat 100% Recht. Dieses Problem würde nicht ausreichen, um die Übernahme einer weiteren Bibliothek zu rechtfertigen. Wenn ich jedoch aus anderen Gründen bereits commons-io verwenden würde, würde ich Filenameutils verwenden.
Jason S
1
@ Jason: Reguläre Ausdrücke: das Geschenk, das immer weiter gibt. :)
Adam Paynter
3
@Bozho - Sarkasmus? Die eigentliche Frage ist, warum Java mit endlosen Haufen redundanter Klassen geliefert wird, die es so einfach machen, das zu tun, was Sie eigentlich wollen, aber dann frustrierend nie wirklich tun. Es gibt kein Äquivalent zu Apache-Commons in Python, da Python einfach alle nützlichen Dinge enthält, die Sie bereits integrieren möchten. C # scheint ein weiteres Beispiel für eine Sprache zu sein, in der Sie sich auf Ihr einzigartiges Problem konzentrieren können, anstatt herausfinden zu müssen, wie Sie das Rad neu erfinden oder das Rad holen können, das jemand anderes erfunden hat.
ArtOfWarfare
84

Alte Frage, aber ich benutze normalerweise diese Lösung:

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 es
quelle
Funktioniert nicht, wenn in Windows gearbeitet wird und der String "Dateiname" "D: \ resources \ ftp_upload.csv" lautet. Können Sie uns bitte helfen?
NIKHIL CHAURASIA
3
@NIKHILCHAURASIA Sie müssen den Backslashes entkommen, indem Sie sie verdoppeln. Wie: "D: \\ resources \\ ftp_upload.csv".
Ricket
8

Quelle: http://www.java2s.com/Code/Java/File-Input-Output/Getextensionpathandfilename.htm

eine solche Utility-Klasse:

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

Verwendung:

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
quelle
4
basename()wäre ein besserer Name anstelle vonfilename()
Nimcap
Falls es keine Erweiterung gibt (z. B. Dateiname wie "/ etc / hosts"), wird "hosts" als Erweiterung zurückgegeben (anstelle von ""). Utility-Klassen in Bibliotheksqualität sollten sich um Eckfälle kümmern.
Zach-M
6

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

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

Java verfügt über integrierte Funktionen, um den Basisnamen und den Verzeichnisnamen für einen bestimmten Dateipfad abzurufen, aber die Funktionsnamen sind nicht so selbstverständlich.

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

quelle
4
java.io.File.getName () gibt den Namen mit der Erweiterung zurück.
Bram
2
Ich denke lieber, dass es so etwas wie "Erweiterung" nicht gibt :-)
3
aber die Frage ist über die Erweiterung zu bekommen ...
user85421
4

Dateierweiterungen sind ein kaputtes Konzept

Und es gibt keine zuverlässige Funktion dafür. Betrachten Sie zum Beispiel diesen Dateinamen:

archive.tar.gz

Was ist die Erweiterung? DOS-Benutzer hätten den Namen bevorzugt archive.tgz. Manchmal sehen Sie dumme Windows-Anwendungen, die zuerst die Datei dekomprimieren (was eine .tarDatei ergibt ), dann müssen Sie sie erneut öffnen, um den Archivinhalt zu sehen.

In diesem Fall wäre ein vernünftigerer Begriff der Dateierweiterung gewesen .tar.gz. Darüber hinaus gibt es .tar.bz2, .tar.xz, .tar.lzund .tar.lzmaDatei „Erweiterungen“ im Einsatz. Aber wie würden Sie entscheiden, ob Sie am letzten oder am vorletzten Punkt teilen möchten?

Verwenden Sie stattdessen MIME-Typen.

Die Java 7-Funktion Files.probeContentType erkennt Dateitypen wahrscheinlich viel zuverlässiger als das Vertrauen in die Dateierweiterung. So ziemlich die gesamte Unix / Linux-Welt sowie Ihr Webbrowser und Smartphone tun dies bereits auf diese Weise.

Hat aufgehört - Anony-Mousse
quelle
6
Wie beantwortet dies die Frage? Weder Filenoch Pathlassen Sie mich die Erweiterung abspalten.
Andreas Abel
@ andreas.abel Lassen Sie mich das wiederholen: Dateierweiterungen sind ein kaputtes Konzept. Sie sind nicht zuverlässig, noch gut definiert sind, außer auf DOS 8 + 3 - Dateinamen (man denke .tar.gzvs. .tgznur allzu häufig auf Unix). Verwenden Sie stattdessen MIME-Typen.
Hat aufgehört - Anony-Mousse
1
@ Anony-Mousse Nun, ich stimme im Prinzip zu, aber 99.999% aller Systeme, mit denen ich interagiere, verwenden einen Dateinamen, keinen MIME-Typ
Christian Sauer
Wo liegt das Problem bei der Verwendung, Files.probeContentTypeanstatt sich auf den Dateinamen zu verlassen, um die richtige Erweiterung zu haben?
Hat aufgehört - Anony-Mousse
3
Dies beantwortet die Frage nicht. Ich habe einen Anwendungsfall, in dem der Dateiname, ein Film, ein Name + eine Erweiterung ist. Wie würde ich den Namen mit MIME-Typen extrahieren?
Niek
1

Was ist los mit deinem Code? Eingewickelt in eine ordentliche Dienstprogrammmethode ist es in Ordnung.

Wichtiger ist, was als Trennzeichen verwendet werden soll - der erste oder letzte Punkt. Der erste ist schlecht für Dateinamen wie "setup-2.5.1.exe", der letzte ist schlecht für Dateinamen mit mehreren Erweiterungen wie "mybundle.tar.gz".

Mot
quelle
-3

Vielleicht könnten Sie String # split verwenden

Um Ihren Kommentar zu beantworten:

Ich bin mir nicht sicher, ob es mehr als eine geben kann. in einem Dateinamen, aber was auch immer, auch wenn es mehr Punkte gibt, können Sie die Aufteilung verwenden. Bedenken Sie zB das:

String input = "boo.and.foo";

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

Dies gibt ein Array zurück, das Folgendes enthält:

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

Sie wissen also, dass der letzte Index im Array die Erweiterung und alle anderen die Basis sind.


quelle
Nun ja, aber ich müsste einen regulären Ausdruck für den letzten .in einer Zeichenfolge herausfinden
Jason S
1
Hmm, ich bin mir nicht sicher, aber kannst du nicht einfach "." Verwenden? Oder sind die mehr als 1 Punkte in einem Dateinamen?
2
Ich denke, das würde funktionieren:fileName.split("\\.(?=[^\\.]+$)")
Adam Paynter
1
Sie können nicht davon ausgehen, dass es nur einen Punkt gibt. Adam: Danke, ich werde es versuchen.
Jason S
4
Diese Antwort ist falsch. Da der Punkt nicht maskiert wird, wird ein leeres Array zurückgegeben.
Aled