解答例 - j2.lesson09.ScoreDatabase

package j2.lesson09;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 課題2203 - 解答例.
 * カンマ区切りで記録された学生の得点一覧ファイルを読み出すクラス.
 @author arakawa
 @version $Id: ScoreDatabase_java.rps,v 1.1 2006/03/06 12:56:15 java2005 Exp $
 */
public class ScoreDatabase {

    private final List students;
    
    /**
     * 学生の得点一覧ファイルの名前を指定してインスタンスを生成する。
     * 得点一覧ファイルは順に次のように格納されている。
     <ul>
     <li> レコード数 - int 型のデータ, 4 bytes </li>
     <li> 下記をレコード数だけ繰り返す
     *   <ul>
     *   <li> 学籍番号 - char 型のデータ 4 個分, 8 bytes</li>
     *   <li> 名前 - char 型のデータ 10 個分, 20 bytes </li>
     *   <li> 得点 - int 型のデータ, 4 bytes</li>
     *   </ul>
     </li>
     </ul>
     * 学籍番号や名前が指定された文字数に満たない場合、末尾は <code>(char) 0</code> で埋められている。
     @param filename 読み出すファイルの名前
     @throws IOException 得点一覧ファイルを読み込んでいる最中に例外が発生した場合
     @throws NumberFormatException 得点が整数でない場合
     */
    public ScoreDatabase(String filenamethrows IOException {
        super();
        List list = new ArrayList();
        char[] id = new char[4];
        char[] name = new char[20];
        DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
        try {
            int count = in.readInt();
            for (int k = 0; k < count; k++) {
                // id を取得
                int idLength = 0;
                for (int i = 0; i < 4; i++) {
                    id[i= in.readChar();
                    if (id[i!= (char0) {
                        idLength++;
                    }
                }
                // name を取得
                int nameLength = 0;
                for (int i = 0; i < 10; i++) {
                    name[i= in.readChar();
                    if (name[i!= (char0) {
                        nameLength++;
                    }
                }
                // score を取得
                int score = in.readInt();
                list.add(new Student(
                    String.valueOf(id, 0, idLength),
                    String.valueOf(name, 0, nameLength),
                    score));
            }
        }
        finally {
            in.close();
        }
        this.students = list;
    }
    
    /**
     * このインスタンスが持つ得点一覧を、指定したファイルに書き出す。
     @param filename 書き込み先のファイル名
     @throws IOException ファイル書き込み中に例外が発生した場合
     */
    public void save(String filenamethrows IOException {
        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(filename)));
        try {
            // 最初に個数を int 型で書き込む
            out.writeInt(this.students.size());
            for (int i = 0; i < this.students.size(); i++) {
                Student std = (Studentthis.students.get(i);
                // id を書き込み (char*4, 8bytes)
                char[] id = std.getId().toCharArray();
                for (int j = 0; j < 4; j++) {
                    if (j < id.length) {
                        out.writeChar(id[j]);
                    }
                    else {
                        out.writeChar((char0);
                    }
                }
                // name を書き込み (char*10, 20bytes)
                char[] name = std.getName().toCharArray();
                for (int j = 0; j < 10; j++) {
                    if (j < name.length) {
                        out.writeChar(name[j]);
                    }
                    else {
                        out.writeChar((char0);
                    }
                }
                // score を書き込み (int, 4bytes)
                out.writeInt(std.getScore());
            }
        }
        finally {
            out.close();
        }
    }

    /**
     * 一覧に含まれる全ての学生を {@link Student} 型を格納している {@link List} で取得する。
     {@link List} 内の順序は、コンストラクタに指定したファイルに記述されている順番に等しい。
     @return 全ての学生を含む {@link List}
     */
    public List getAllStudent() {
        return this.students;
    }
    
    /**
     * 一覧に含まれる学生のうち、<code>grade</code>で指定した成績を持つ学生を取得する。
     * このクラスが返す {@link List} は該当する学生を表す {@link Student} クラスのインスタンスを全て含む。
     {@link List} 内の順序は、コンストラクタに指定したファイルに記述されている順番に等しい。
     @param grade 取得する学生の成績
     @return 指定した成績を持つ学生を含む {@link List} 
     @throws IllegalArgumentException 引数に <code>'A', 'B', 'C', 'D'</code> 以外のいずれかが指定された場合
     */
    public List getStudents(char grade) {
        if (grade != 'A' && grade != 'B' && grade != 'C' && grade != 'D') {
            throw new IllegalArgumentException("grade = " + grade);
        }
        List stds = this.students;
        List list = new ArrayList();
        for (int i = 0; i < stds.size(); i++) {
            Student student = (Studentstds.get(i);
            if (student.getGrade() == grade) {
                list.add(student);
            }
        }
        return list;
    }
    
    /**
     * テストプログラム。
     @param args 無視される
     */
    public static void main(String[] args) {
        ScoreDatabase sdb;
        try {
            sdb = new ScoreDatabase("U:/ex2203test.dat");
        }
        catch (IOException e) {
            System.out.println("U:/ex2203test.datが開けません");
            return;
        }
        List all = sdb.getAllStudent();
        System.out.println("全体の人数=" + all.size());
        List as = sdb.getStudents('A');
        printList('A', as);
        List bs = sdb.getStudents('B');
        printList('B', bs);
        List cs = sdb.getStudents('C');
        printList('C', cs);
        List ds = sdb.getStudents('D');
        printList('D', ds);
    }

    private static void printList(char grade, List list) {
        System.out.println(grade + "の学生:");
        for (int i = 0; i < list.size(); i++) {
            System.out.println("  " + list.get(i));
        }
    }
}