2012年4月17日火曜日

Get a file's content as String in Java

public static String toString(File file, Charset charset) throws IOException
{
    if (file == null)
    {
        // Error. 'file' argument is mandatory.
        throw new IllegalArgumentException("file is null.");
    }

    if (charset == null)
    {
        // Use the default charset of the platform.
        charset = Charset.defaultCharset();
    }

    if (Integer.MAX_VALUE < file.length())
    {
        // The file size is too big.
        throw tooBig(file, null);
    }

    // InputStream to read the content of the file from.
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));

    try
    {
        // Create a byte array having the same size as the file.
        byte[] content = new byte[(int)file.length()];

        // Read all the bytes of the file into the byte array.
        in.read(content);

        // Convert the byte array into a String instance.
        return new String(content, charset);
    }
    catch (OutOfMemoryError e)
    {
        // new byte[] (or new String) failed. The file size is too big.
        throw tooBig(file, e);
    } 
    finally
    { 
        try
        {
            in.close();
        }
        catch (IOException e)
        {
        }
    }
}

private static IOException tooBig(File file, Throwable cause)
{
    String format = "The file '%s' is too big (%,d bytes).";

    String message = String.format(format, file.getAbsolutePath(), file.length());

    if (cause != null)
    {
        return new IOException(message, cause);
    }
    else
    {
        return new IOException(message);
    }
}


An excerpt from the online Java API document of java.nio.channels.FileChannel#map method:

For most operating systems, mapping a file into memory is more expensive than reading or writing a few tens of kilobytes of data via the usual read and write methods. From the standpoint of performance it is generally only worth mapping relatively large files into memory.



After that, I noticed readFileToString(File file, Charset encoding) method of FileUtils class of Apache Commons IO provides the same functionality (although I don't know its implementation). The wheel again... I should check Apache Commons first before starting something.



ファイルの内容をStringとして取得する (Java)

public static String toString(File file, Charset charset) throws IOException
{
    if (file == null)
    {
        // エラー。file 引数は必須。
        throw new IllegalArgumentException("file が null です。");
    }

    if (charset == null)
    {
        // プラットフォームのデフォルトのキャラクターセットを使う。
        charset = Charset.defaultCharset();
    }

    if (Integer.MAX_VALUE < file.length())
    {
        // ファイルサイズが大き過ぎる。
        throw tooBig(file, null);
    }


    // ファイルの内容を読み込むための InputStream
    BufferedInputStream in = new BufferedInputStream(new FileInputStream(file));

    try
    {
        // ファイルと同じサイズを持つ byte 配列を作成する。
        byte[] content = new byte[(int)file.length()];

        // ファイルの全てのバイトを byte 配列に読み込む。
        in.read(content);

        // byte 配列を String に変換する。
        return new String(content, charset);
    }
    catch (OutOfMemoryError e)
    {
        // new byte[] (もしくは new String) が失敗した。ファイルサイズが大き過ぎる。
        throw tooBig(file, null);
    }
    finally
    {
        try
        {
            in.close();
        }
        catch (IOException e)
        {
        }
    }
}


private static IOException tooBig(File file, Throwable cause)
{
    String format = "ファイル「%s」は大き過ぎます (%,d バイト)";

    String message = String.format(format, file.getAbsolutePath(), file.length());

    if (cause != null)
    {
        return new IOException(message, cause);
    }
    else
    {
        return new IOException(message);
    }
}


java.nio.channels.FileChannel#map メソッドのオンライン Java API ドキュメントからの抜粋:

ほとんどのオペレーティングシステムでは、ファイルをメモリーにマッピングするほうが、通常の read メソッドまたは write メソッドを使って数十キロバイトのデータの読み込みまたは書き込みを行うよりも負荷が大きくなります。性能を重視するなら、比較的大きめのファイルだけをマッピングすることをお勧めします。



その後、Apache Commons IOFileUtils クラスの readFileToString(File file, Charset encoding) メソッドが同じ機能を提供していることを知った(実装はどうなっているか知らないけど)。車輪開発してしまった。これからは、何かやるときは Apache Commons を調べてからにしよう。