2012年7月26日木曜日

[Java][SV]SVファイルIO(ソースコード)

package util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * セパレーテッドバリューファイル
 */
public class SvFile {

    /** デリミタ */
    private String delm = null;

    /** SV行データリスト */
    List<List<String>> svLineList = null;

    public List<List<String>> getSvLineList() {
        return svLineList;
    }

    public void setSvLineList(List<List<String>> svLineList) {
        this.svLineList = svLineList;
    }

    /**
     * コンストラクタ
     */
    public SvFile() {
    }

    /**
     * 指定されたファイルのデータを読み込みます。デリミタを指定しないコンストラクタの場合、デリミタはタブとなります。
     *
     * @param fileName
     *            ファイル名
     * @throws IOException
     */
    public void loadFile(String fileName) throws IOException {

        // SVファイルをロードする
        loadFile(fileName, "\t", false);
    }

    /**
     * デリミタを区切り文字として、指定されたファイルのデータを読み込みます。最初の行は読み飛ばしません。
     *
     * @param fileName
     *            ファイル名
     * @param delm
     *            デリミタ
     * @throws IOException
     */
    public void loadFile(String fileName, String delm) throws IOException {

        // SVファイルをロードする
        loadFile(fileName, delm, false);
    }

    /**
     * デリミタを区切り文字として、指定されたファイルのデータを読み込みます。
     *
     * @param fileName
     *            ファイル名
     * @param delm
     *            デリミタ
     * @param skipFirstLine
     *            最初の行を読み飛ばす場合はtrue、そうでなければfalse
     * @throws IOException
     */
    private void loadFile(String fileName, String delm, boolean skipFirstLine)
            throws IOException {

        // デリミタを記憶しておく
        this.delm = delm;

        // SV行データリストを初期化する
        setSvLineList(new ArrayList<List<String>>());

        // ファイルを開く
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(new File(fileName)));

            // 最初の行をスキップする設定の場合は、読み捨てを行う
            String line = "";
            if (skipFirstLine) {
                line = br.readLine();
            }

            // 全ての行を処理するまでループ
            while ((line = br.readLine()) != null) {

                // SV行のデータをロードする
                loadLine(line);
            }

            // 最後に必ずファイルを閉じる
        } finally {
            if (br != null) {
                br.close();
            }
        }
    }

    /**
     * SVファイルの行データをロードします。SV値は改行なし、ダブルクオートによるエスケープもなしと前提します。
     *
     * @param line
     *            行データ
     */
    private void loadLine(String line) {

        // 文字列をスプリッタで分割する
        String[] svValArray = line.split(delm);

        // 行データ内の全てのSV値を処理するまでループ
        List<String> svValList = new ArrayList<String>();
        for (String svVal : svValArray) {

            // 【重要!】null値を検出した場合は空文字列を設定する
            if (svVal.equals("(null)")) {
                svValList.add("");
            }

            // 【重要!】SV値はダブルクオートで囲むルールとする
            else if (svVal.length() == "".length()) {
                svValList.add("");
            } else if (svVal.startsWith("\"") && svVal.endsWith("\"")) {
                svValList.add(svVal.substring(1, (svVal.length() - 1)));
            }
        }

        // リストに行データを追加する
        getSvLineList().add(svValList);
    }

    /**
     * 引数で指定されたSV行データリストで既存のデータを上書きします。
     *
     * @param fileName
     *            ファイル名
     * @param delm
     *            デリミタ
     * @param svLineList
     *            SV行データリスト
     * @throws IOException
     */
    public void save(String fileName, List<List<String>> svLineList)
            throws IOException {

        // セーブする
        save(fileName, "\t", svLineList);
    }

    /**
     * 引数で指定されたSV行データリストで既存のデータを上書きします。
     *
     * @param fileName
     *            ファイル名
     * @param delm
     *            デリミタ
     * @param svLineList
     *            SV行データリスト
     * @throws IOException
     */
    public void save(String fileName, String delm, List<List<String>> svLineList)
            throws IOException {

        BufferedWriter bw = null;
        try {
            // ファイルを書き込み用に開く
            bw = new BufferedWriter(new FileWriter(new File(fileName)));

            // 全ての行データを処理するまでループ
            for (List<String> svLine : svLineList) {

                // SV行データの各カラムをデリミタで接続する
                StringBuffer sb = new StringBuffer("");
                for (String column : svLine) {

                    // 1つ以上のカラムをSV行に設定している場合は、区切り文字を入れる
                    if (sb.length() > 0) {
                        sb.append(delm);
                    }

                    // 【重要!】空文字列はnull値として記録する
                    if (column == null || column.length() == 0) {
                        sb.append("(null)");
                    }

                    // 【重要!】SV値はダブルクオートで囲むルールとする
                    else {
                        sb.append("\"" + column + "\"");
                    }
                }

                // ファイルに書き込みを行い、最後に改行を入れる
                bw.write(sb.toString());
                bw.newLine();
            }

        } finally {

            // ファイルをクローズする
            bw.close();
        }
    }
}