倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

これからの「Java I/O」の話をしようwww (11) : Files クラスのメソッド ~MIME Type を調べる~

Java nio の API を見ていくシリーズ(目次)。 Files クラスのメソッドがあと少し残っているので回収記事をサラリと。 今回はファイルの MIME Type を調べるメソッド Files#probeContentType() メソッド。

MIME type とは XML に対しての「text/xml」みたいなヤツです。 簡単にはファイルの拡張子で分かりますが、真面目な実装だとファイルの内容とかも解析するんでしょうね。 Files#probeContentType() メソッドは結構実装に依存するようで、OS などによって結果は変わりうるそうです。

probeContentType() メソッドの使い方

Files#probeContentType() メソッドの使い方は簡単です。

import java.io.IOException;
import java.nio.file.*;

public class ProbeContentTypeSample {

    public static void main(String... args)throws IOException{
        // Java ファイル
        Path java = Paths.get("./src/ProbeContentTypeSample.java");
        System.out.println(Files.probeContentType(java));    // 「null」と表示

        // クラスファイル
        Path clazz = Paths.get("./out/production/nio-test/ProbeContentTypeSample.class");
        System.out.println(Files.probeContentType(clazz));    // 「null」と表示

        // XML ファイル
        Path xml = Paths.get("./.idea/workspace.xml");
        System.out.println(Files.probeContentType(xml));    // 「text/xml」と表示

        // JavaScript ファイル
        Path js = Paths.get("C:/javascript/threejs/build/three.js");
        System.out.println(Files.probeContentType(js));    // 「null」と表示
    }
}

MIME Type が判定できない場合は null が返されます。 Java ファイルもクラスファイルもデフォルトでは null が返されるようですね。 XML ファイルは「text/xml」になってます。 ちなみに、デフォルト実装では拡張子だけで判定しているのか、ファイルが存在しなくても例外が投げられたりしません(OS などに依るかもしれませんが)。

独自の判定アルゴリズムを追加する

もちろん自分で判定アルゴリズムを書いて MIME Type の判定に使うこともできます。 これには ServiceLoader の仕組みを使います。 手順は

  1. java.nio.file.spi.FileTypeDetector クラスのサブクラスを作成する
  2. META-INF/services/java.nio.file.spi.FileTypeDetector ファイルを作成し、作成した FileTypeDetector クラスの完全修飾名を書く
  3. 通常の Files#probeContetyType() メソッドを使って MIME Type を判定できる

です。 まぁ、最近は ServiceLoader を使うのも結構標準的な手法になってると思うのでそんなに難しくないかと思います。

ではちょっと試してみましょう。 ここでは、拡張子が「.js」のファイルの MIME Type を「text/javascript」と判定するようにしましょう(先ほどのサンプルでは null が返されてました)。 MIME Type の判定アルゴリズムは FileTypeDetector のサブクラスの probeContentType() メソッドの実装に書きます。 他に実装すべきメソッドは無いので簡単。

package org.waman.nio;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.spi.FileTypeDetector;

public class MyFileTypeDetector extends FileTypeDetector {

    @Override
    public String probeContentType(Path path) throws IOException {
        if(path.getFileName().toString().endsWith(".js")){
            return "text/javascript";
        }else{
            return null;
        }
    }
}

次はこのクラスが Files#probeContentType() メソッド呼び出し時に認識されるように、サービスとして登録します。 まぁ、何てことはなくて、テキストファイルを1つ追加するだけ。 ソース・ディレクトリに「META-INF/services」というディレクトリを作成して「java.nio.file.spi.FileTypeDetector」というファイルを作成し、内容のテキストとして先ほど作成した FileTypeDetector のサブクラスの完全修飾名を書きます:

org.waman.nio.MyFileTypeDetector

ちなみに、プロジェクトのディレクトリ構造が Maven2/3 風のビルドツール(Gradle, sbt などを含む)を使っている場合は、

  • 《プロジェクト・ルート》/src/main/resources/META-INF/services

フォルダに上記のファイルを配置して下さい。

さて、これで準備が完了。 あとは普通に Files#probeContentType() メソッドを使うだけです。 上記と同じサンプルコードを実行すると

import java.io.IOException;
import java.nio.file.*;

public class ProbeContentTypeSample {

    public static void main(String... args)throws IOException{
        // Java ファイル
        Path java = Paths.get("./src/ProbeContentTypeSample.java");
        System.out.println(Files.probeContentType(java));    // やっぱり「null」と表示

        // クラスファイル
        Path clazz = Paths.get("./out/production/nio-test/ProbeContentTypeSample.class");
        System.out.println(Files.probeContentType(clazz));    // やっぱり「null」と表示

        // XML ファイル
        Path xml = Paths.get("./.idea/workspace.xml");
        System.out.println(Files.probeContentType(xml));    // やっぱり「text/xml」と表示

        // JavaScript ファイル
        Path js = Paths.get("C:/javascript/threejs/build/three.js");
        System.out.println(Files.probeContentType(js));    // 「text/javascript」と表示!
    }
}

となって、javascript ファイルの MIME Type がキチンと返されました!

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)