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を 見てくださいFilenameUtilsgetBaseName(..)getExtension(..)メソッドがあります。
Bozho 2010

拡張機能についてのみstackoverflow.com / questions / 3571223 /…を参照してください。
アンディトーマス

回答:


168

他の人が言及していることは知ってString.splitいますが、これは2つのトークン(ベースと拡張)のみを生成するバリアントです。

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

例えば:

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

収量:

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

正規表現は、Javaに、任意の数の非ピリオドが続き、その後に入力の終わりが続く任意のピリオドで分割するように指示します。この定義に一致する期間は1つだけです(つまり、最後の期間)。

技術的には、この手法は、ゼロ幅のポジティブルックアヘッドと呼ばれます


ところで、パスを分割して、ドット拡張子を含むがこれに限定されない完全なファイル名を取得する場合は、スラッシュ付きのパスを使用します。

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

例えば:

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

2
なぜ人々が依存関係を恐れているのか
分かり

3
@Bozho:私は図書館がこの種の問題のより良い解決策であることに同意します。それは他の人々があなたのために維持し、考えることを可能にします(それが私があなたの答えに賛成票を投じた理由です!)。これは些細なことのように聞こえるかもしれませんが、過去にいくつかの問題で「JAR地獄」に苦しんでいたため、Apacheライブラリを含めることを検討するときに常に躊躇する部分があります(私は知っています、それは些細なことです)。
Adam Paynter 2010

4
@Bozho:アダムの100%正しい。この問題は、私がさらに別のライブラリを使用することを保証するのに十分ではありませんが、他の理由ですでにcommons-ioを使用している場合は、Filenameutilsを使用します。
ジェイソンS

1
@ジェイソン:正規表現:与え続ける贈り物。:)
Adam Paynter 2011年

3
@ Bozho-皮肉?本当の問題は、Javaには、実際にやりたいことを簡単に実行できるようになる冗長クラスが無限に山積みされているのに、イライラするほど実際には実行できないのはなぜかということです。Pythonには、必要なすべての便利な機能がすでに組み込まれているだけなので、PythonのApache-Commonsに相当するものはありません。C#は、車輪の再発明や他の誰かが発明した車輪の再発明の方法を理解する代わりに、独自の問題に集中できる言語のもう1つの例のようです。
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 2016年

3
@NIKHILCHAURASIAバックスラッシュを2倍にして、エスケープする必要があります。例:「D:\\ resources \\ ftp_upload.csv」。
くる病2016年

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 2012

拡張子がない場合(「/ 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には、特定のファイルパスのベース名とdirnameを取得するための組み込み関数がありますが、関数名はそれほど自明ではありません。

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

4
java.io.File.getName()は、拡張子付きの名前を返します。
ブラム

2
「拡張」のようなものはないと思いたいです:

3
しかし、問題は拡張機能の取得についてです...
user854 2119

4

ファイル拡張子は壊れた概念です

そして、それに対する信頼できる機能は存在しません。たとえば、次のファイル名について考えてみます。

archive.tar.gz

拡張子何ですか?DOSユーザーは名前を好むでしょうarchive.tgz。時には、あなたが見愚かなWindowsアプリケーションをその最初の解凍ファイル(降伏.tarファイル)を、その後、アーカイブの内容を見るためにそれを再度開く必要があります。

この場合、ファイル拡張子のより合理的な概念はでした.tar.gz。そこでもある.tar.bz2.tar.xz.tar.lzおよび.tar.lzma使用中のファイル「拡張子が」。しかし、最後のドットで分割するか、最後から2番目のドットで分割するかをどのように決定しますか?

代わりにmime-typesを使用してください。

Java 7関数Files.probeContentTypeは、ファイル拡張子を信頼するよりも、ファイルタイプを検出する方がはるかに信頼性が高い可能性があります。ほぼすべてのUnix / Linuxの世界、およびWebブラウザとスマートフォンはすでにこの方法でそれを行っています。


6
これはどのように質問に答えますか?どちらFilePath私は拡張子をオフに分割してみましょうありません。
アンドレアスアベル

@ andreas.abelこれを繰り返します:ファイル拡張子は壊れた概念です。彼らは信頼性の高い、またDOS 8 + 3ファイル名を除いて、明確に定義されていない(考える.tar.gz.tgzUNIX上で、あまりにも共通)。代わりにmimeタイプを使用してください。
-匿名-ムース2018年

1
@ Anony-Mousseええと、私は原則的に同意しますが、私がやり取りするすべてのシステムの99,999%は、mimeタイプではなく、ファイル名を使用しています
ChristianSauer19年

Files.probeContentType正しい拡張子を持つためにファイル名に依存する代わりに使用する際の問題はどこにありますか?
-匿名-ムース

3
これは質問に答えません。映画のファイル名が名前+拡張子であるユースケースがあります。mime-typesを使用して名前を抽出するにはどうすればよいですか?
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("\\.(?=[^\\.]+$)")
Adam Paynter 2010

1
ドットが1つしかないことは想定できません。アダム:ありがとう、やってみます。
ジェイソンS

4
この答えは正しくありません。ドットはエスケープされていないため、空の配列を返します。
2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.