ざっくりJava〜ファイル読み書き〜

#ファイルの読み込みと書き込み

##ファイル読み書きの基本手順
```
ファイルを１回開く　➡　ファイルのデータを読み込む、書き込む　➡　ファイルを１回閉じる
```

##読み書きの方法
プログラムがファイルを読み書きする方法は「ランダムアクセス」と「シーケンシャルアクセス」がある。

```
ランダムアクセス　・・・　ファイルのあちこちに自由に読み書きできる。その文読み書き速度が遅い
シーケンシャルアクセス　・・・　先頭から順番にしか読み書きできない。読み書き速度が速い
```

※ファイルの書き込みは書き込む文字数があらかじめ分かるが、読み込みは文字数が予め分からない。
※ファイルの読み書きは基本１つずつ。
※テキストの読み書き時の文字コードはシステム標準のものを使ってる

##ディレクトリ作成やファイル作成、パス指定
ファイル作成などは`Fileクラス`を使う。
パスを指定する時は「¥¥」で区切る「区切り文字」を使うが、OSによってこの区切り文字が違う。
Windowsでは「￥」、Linux・Unixでは「/」
Fileクラスの「separator」を使ってOSが違ってもプログラムを書き換える必要をなくす。 

※ちなみに、WindowsではCドライブやDなどドライブ装置がいくつもあるが、Linux・Unixでは記憶装置を１つに統合しているので左端がドライブ名ではなく「/（ルートディレクトリ）」から始まる。

```java
import java.io.File;  //Fileクラス読み込み

String FS = File.separator;
File f = new File("c:"+FS+"data"+FS+"sys"); //　変数に入れたセパレータで区切
boolean rst = f.mkdirs(); //ディレクトリ作成(既にディレクトリがあればfalse)
System.out.println("結果："+rst);

if(f.exists()){ //ファイルやディレクトリがあるか調べる
  System.out.println("存在します");
}

if(f.isFile()){ //ファイルかどうか調べる
  System.out.println("ファイルです");
}

if(f.isDirectory()){ //ディレクトリかどうか調べる
  System.out.println("ディレクトリです");
}

String[] list = f.list()){ //指定ディレクトリ内のファイル名のリストを取得する
```

##書き込み
`FileWriterクラス`と`BufferedWriterクラス`を使う。
FileWriterクラスだけでも書き込めるが、毎回毎回、１文字？ずつ書き込んでいくので効率が悪い。
BufferedWriterクラスを使うことで、書き込む文字をある程度溜めていき、一気に書き込める。
さらに、出力の際には書式付出力ができるPrintWriterクラスを使うといい。

※書き込む際にはBufferedWriterクラス内にFileWriterクラスの参照を持っているメンバがあり、それが使われる。

```java:例
import java.io.*; //java.io.*でFileクラスとかFileWriterとか全部使えるようにする

public class Sample{
  public static void mian(String[] args){
  FileWriter fw = null;
  BufferedWriter bw = null;
  PrintWriter pw = null;
  try{
       String FS = File.separator;
       File f = new File("c:"+FS+"data"+FS+"sys"+FS+"sample.txt");

       fw = new FileWriter(f,true); //書き込むファイル指定。ファイルが既にあるなら、そのファイルの末尾に書き込む
       bw = new BufferedWriter(fw); //バッファクラスでfwを包んであげる
        pw = new PrintWriter(bw); //さらに、PrintWriterで包む

       pw.write("書き込む内容１行目"); //　行単位でデータ出力
        pw.write("書き込む内容２行目");
       
       pw.close(); //ファイル閉じる
  }catch(IOException e){
     System.out.println("エラー："+e);
     try{
       if(pw != null) pw.close(); //エラーが起きた場合でも閉じるようにする（Java7では不要）
     }catch(IOException e2){ } //　何もしない
  }
  }
}
```

##読み込み

```java:例
import java.io.*; //java.io.*でFileクラスとかFileWriterとか全部使えるようにする

public class Sample{
  public static void mian(String[] args){
  FileReader fr = null;
  BufferedReader br = null;
  try{
       String FS = File.separator;
       File f = new File("c:"+FS+"data"+FS+"sys"+FS+"sample.txt");

       fr = new FileReader(f); //書き込むファイル指定。ファイルが既にあるなら、そのファイルの末尾に書き込む
        br = new BufferedWriter(fr); //バッファクラスでfwを包んであげる
        String s;
       while((s=br.readLine()) != null){ //readLine()で１行ずつ読み込んでいく
                 //いろいろな処理
       }
       
       br.close(); //ファイル閉じる
  }}catch(IOException e){
     System.out.println(e);
     try{
       if(pw != null) pw.close(); //エラーが起きた場合でも閉じるようにする（Java7では不要）
      }catch(IOException e2){ } //　何もしない
  }
  }
}
```

##バイナリファイルにバイト列を読み込む・書き込む
テキストファイルの読み書きのやり方と一緒。

```java
import java.io.*;
public class Test{
    public static void main(String args[]){
         try{
              FileOutputStream fos = new FileOutputStream("rpgsave.dat",true);
              FileInputStream fis = new FileInputStream("rpgsave.dat",true);
              fos.write(65);  //６５は２進数で「01000001」
              fos.flush();     fos.close();

         }catch(IOException e){
              System.ou.println(e);
         }         
    }
}
```

#フィルタをストリームに挟んで、変換する
フィルタには色々なものがネットとかでも出回ってる。暗号化とか。
フィルタは単独でnewできない。
フィルタはいくつでもセットできる。

```java:例
FileOutputStream fos = new FileOutput Stream("data.txt");
CipherOutputStream cos = new CipherOutputStream(fos); //暗号化フィルタをfosにセット
WriterOutputStream wos = new WriteOutputStream(cos); //さらに文字バイト変換のフィルタをセットもOK
wos.write("AB");
wos.close();
```


#いろいろなファイル形式

##データフォーマットとは？
例えば、個人のデータを保存したい場合「名前、年齢、住所」の様に保存するが、
書き込み時に「名前、住所、年齢」と順番を変えてしまったらちゃんと読み込めなくなる。
なので、あらかじめどういう形式で読み書きするかを決めておくのがデータフォーマット。

##CSV
カンマで区切られる。エクセルなどでも編集可能。

##プロパティファイル
中身が見て分かりやすい。
「.properties」拡張子を使う
キーと値をペアにして保存。ペアデリミタは「=」「:」を使う。
「＃」や「！」で始まる行はコメントとして無視される

```java
import java.util.*; //　⬅　この中に入ってる
public class Test{
    public static void main(Strin args[]){
         try{
              Reader fr = new FileReader("rpgdata.properties");
              Properties p = new Properties();
              p.load(fr); //　⬅　ファイル内容を読み込む
              String name = p.getProperty("myName"); //　⬅　キーを指定して値を取得
              p.setProperty("myName", "さいとう"); //　⬅　キーを指定して値をセット
              p.store(fw,"自分の情報"); //　⬅　ファイルへ書き出す。引数にコメントを入れられる。
              fr.close();
         }catch( ...
```
※Java5以前までは日本語などをiプロパティファイルへ記述できなかった。

##XML形式
入れ子構造のデータ保存に使える
JSONやJAXPというAPIを使って読み書きできる。

##Javaの直列化
Java直列化を使って、インスタンスの内容をまるごと一気にバイト列へ変換して保存できる。
いちいちインスタンスのフィールドごとにひとつひとつ保存する記述を書く必要がない。
複雑な構造のデータでも、バイト列に変換して保存・読み込みしてくれる。
直列化するクラスにはSerializableインターフェースをimplementsしておく。

※フィールドもインスタンスの場合はそのインスタンスもSerializableがimplementsされてること
※ static , transientがついたフィールドは直列化の対象にならない！！

```java
import java.io.*;
public class Hero implements Serializable{
     
     //...

     Sample s = new Sample("きむ",75,18);
     FileOutputStream fos = new FileOutputStream("rpgsave.dat");
     ObjectOutputStream oos = new ObjectOutputStream(fos); //　書き出すファイルパスをセット
     oos.writeObject(s); //　バイト列へ変換して書き出し
     oos.flush();
    FileInputStream fis = new FileInputStream("rpgsave.dat");
     ObjectInputStream ois = new ObjectInputStream("fis"); 
     Sample s2 = (Sample) ois.readObject();  //　バイト列からインスタンスへ変換し読込み
     oos.close(); ois.close();
```