Ch.8 入出力

Fileクラス

ファイル名やディレクトリ名の取得に用いられる。

import java.io.File;
import java.util.Arrays;

public class FileIO {
    public static void main (String args[]){
        File thisDr = new File("C:\\Users\\broad\\Desktop");
        Arrays.stream(thisDr.listFiles()).forEach(a -> System.out.println(a.getName()+ " isDir? : " + a.isDirectory()));
        //'desktop.ini isDir? : false'
        //'Java Gold取得計画.lnk isDir? : false'
        //'my-account-book isDir? : true'
        //'my-account-book-server isDir? : true'
        System.out.println("file.separator : " + System.getProperty("file.separator")); //'\'
        System.out.println("line.separator : " + System.lineSeparator().toUpperCase()); //
        System.out.println("path.separator : " + System.getProperty("path.separator")); //';'
    }
}

ストリーム

Javaでは「ストリーム」を用いて、ファイルの中身の読み書きを行う。 「ストリーム」の利用法は主に3通り存在する。

出力クラス 出力単位 備考
FileInput/OutputStream byte単位 バイナリファイル向け
DateInput/OutputStream 基本データ型(int String)単位 FileOutputStreamとの併用
FileReader/Writer char単位 テキストファイル向け
BufferedReader/Writer 文字列単位  FileWriterとの併用

FileOutputStream(単体)

import java.io.*;
import java.nio.charset.StandardCharsets;

public class FStream {
    public static void main (String[] args){
        try(
                FileOutputStream fos = new FileOutputStream(new File("C:\\Users\\broad\\Desktop\\test.txt"));
                FileInputStream  fis = new FileInputStream (new File("C:\\Users\\broad\\Desktop\\test.txt"))
        ) {
            fos.write("もふもふの犬".getBytes(StandardCharsets.UTF_8));
            int data = 0;
            while ((data != -1)){
                System.out.println(data);
                data = fis.read();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } ;
    }
}

f:id:Pyons:20210411082534p:plain
FileOutputStreamでの書き出し

0
227
130
130
227
129
181
227
130
130
227
129
181
227
129
174
231
138
172

DataOutputStream(FileOutputStream併用)

import java.io.*;

public class DIOStream {
    public static void main (String[] args){
        try(
                DataOutputStream dos = new DataOutputStream(new FileOutputStream("C:\\Users\\broad\\Desktop\\test.txt"));
                DataInputStream  dis = new DataInputStream (new FileInputStream("C:\\Users\\broad\\Desktop\\test.txt"));
        ) {
            dos.writeInt(873);
            dos.writeUTF("お花見");
            dos.writeUTF("花見");

            System.out.println(dis.readInt()); //'873'
            System.out.println(dis.readUTF()); //'お花見'
            System.out.println(dis.readUTF());    //'130'

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } ;
    }
}

f:id:Pyons:20210411085634p:plain
DataOutpustStreamでの書き出し(intによる出力が文字化けしている)

FileReaderクラス

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FWriter {
    public static void main(String[] args){
        try(
                FileWriter fw = new FileWriter(new File("C:\\Users\\broad\\Desktop\\test.txt"));
                FileReader fr = new FileReader(new File("C:\\Users\\broad\\Desktop\\test.txt"))) {
            fw.write("えりんぎ まつたけ ぶなしめじ");//Char単位の読み書きを扱うが、文字列も渡せる。
            fw.flush();
            int i = 0;
            while(i != -1){
                i = fr.read();
                System.out.println(i);
                System.out.println((char)i);
            }
                }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
}
12360
え
12426
り
12435
ん
12366
ぎ
32
 
12414
ま
12388
つ
12383
た
12369
け
32
 
12406
ぶ
12394
な
12375
し
12417
め
12376
じ
-1
￿

f:id:Pyons:20210411103926p:plain
FileWriteクラスでの書き出し

BufferdReaderクラス

import java.io.*;

public class BWriter {
    public static void main(String[] args){
        try(
                BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\broad\\Desktop\\test.txt"));
                BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\broad\\Desktop\\test.txt"));
        ){
            bw.write("うまい");
            bw.newLine();
            bw.write("やすい");
            bw.newLine();
            bw.write("はやい");
            bw.newLine();
            bw.flush();

            String data = null;

            while((data = br.readLine()) != null){
                System.out.println(data);
            }

        }catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

f:id:Pyons:20210411110705p:plain
BufferedWriterクラスによる書き出し

BufferedStreamクラスではmarkという、アンカーのようなメソッドがサポートされている。 markで設定した位置にはresetで戻ることが出来る。

            bw.write("東京品川新横浜小田原熱海三島新富士静岡");
            bw.newLine();
            bw.write("掛川浜松豊橋三河安城名古屋岐阜羽島米原");
            bw.newLine();
            bw.write("京都新大阪新神戸西明石姫路相生岡山新倉敷");
            bw.newLine();
            bw.flush();

            String data = null;

            System.out.println(br.readLine());//'東京品川新横浜小田原熱海三島新富士静岡'
            br.mark(100);
            System.out.println(br.readLine());//'掛川浜松豊橋三河安城名古屋岐阜羽島米原'
            br.reset();
            System.out.println(br.readLine());//'掛川浜松豊橋三河安城名古屋岐阜羽島米原'
            br.skip(4);
            System.out.println(br.readLine());//'阪新神戸西明石姫路相生岡山新倉敷'

markの引数としてわたしている数は「これ以上の数を読み込むと、resetで元の位置に戻ることに失敗してしまう可能性がある数」だそう。

BufferedReader (Java Platform SE 8)

Systemクラスの定数

標準入出力もStreamによって処理されている。 標準出力のStreamは各クラスの定数として存在する。

出力クラス クラス定数名
InputStream System.in
PrintStream System.out
PrintStream System.err

シリアライズ

import java.io.*;

public class Serialize {
    public static void main(String[] args){
        try(ObjectOutputStream objectOutStream = new ObjectOutputStream(new FileOutputStream("C:\\Users\\broad\\Desktop\\javaSerial.txt"));
            ObjectInputStream  objectInputStream = new ObjectInputStream(new FileInputStream("C:\\Users\\broad\\Desktop\\javaSerial.txt"))
        ){
            MyClass obj = new MyClass();
            obj.method();
            System.out.println(obj.message);

            objectOutStream.writeObject(obj);
            MyClass b = (MyClass)objectInputStream.readObject();
            System.out.println(b.message);

            MySecondClass obj2 = new MySecondClass();
            obj2.method();
            System.out.println(obj2.message);

            objectOutStream.writeObject(obj2);
            MySecondClass c = (MySecondClass) objectInputStream.readObject();
            System.out.println(c.message);

        } catch (IOException | ClassNotFoundException  e ) {
            e.printStackTrace();
        }
    }
}

class MyClass implements Serializable {
    public  String message;

    MyClass(){
        System.out.println("コンストラクタ");
    }
    public void method(){
        this.message = "Hello";
    }
}

class MySecondClass extends  MyClass{
    @Override
    public void method() {
        this.message = "Goodbye";
    }
}

シリアライズで読みだすときは、そのクラスのコンストラクタが同時に呼び出される。

子クラスをシリアライズして読みだすとき、その子クラスの親クラスがSerializableインターフェースを実装しているかどうかで挙動が異なる。 親クラスがSerializableインターフェースを実装していない場合、読みだすときに親クラスのコンストラクタが同時に呼び出される。

package Serialize2;
import java.io.*;

public class Serialize2 {
    public static void main(String[] args){
        try(
                ObjectOutputStream objectOutStream = new ObjectOutputStream(new FileOutputStream("C:\\Users\\broad\\Desktop\\javaSerial.txt"));
                ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("C:\\Users\\broad\\Desktop\\javaSerial.txt"))
        ){
            Dictionary obj = new Dictionary();
            System.out.println(obj.thisIstransent);
            objectOutStream.writeObject(obj);
            Dictionary b = (Dictionary) objectInputStream.readObject();
            System.out.println(b.thisIstransent);
            System.out.println(b.thisIstransent2);
            //'親クラスのコンストラクタ'
            //'子クラスのコンストラクタ'
            //'Hello Transient'
            //'親クラスのコンストラクタ'
            //null
            //null

            Fighter obj2 = new Fighter();
            objectOutStream.writeObject(obj2);
            Fighter c = (Fighter) objectInputStream.readObject();
            System.out.println(c);
            //'親クラスのコンストラクタ'
            //'子クラスのコンストラクタ
            //'Serialize2.Fighter@4de8b406'

        } catch (IOException | ClassNotFoundException  e ) {
            e.printStackTrace();
        }
    }

}

class Book{
    Book(){
        System.out.println("親クラスのコンストラクタ");
    }
}

class Dictionary extends Book implements Serializable{
    public transient String thisIstransent = "Hello Transient";
    public transient String thisIstransent2;

    Dictionary(){
        System.out.println("子クラスのコンストラクタ");
        thisIstransent2 = "this is also transient";
    }
}

class Airplane implements Serializable{
    Airplane(){
        System.out.println("親クラスのコンストラクタ");
    }
}

class Fighter extends Airplane implements Serializable{
    Fighter(){
        System.out.println("子クラスのコンストラクタ");
    }

}

上記のDictionaryクラスからもわかるようにtransientキーワードのついた変数はたとえクラス内で初期化されていても、シリアライズされない。 これはコンストラクタで初期化されていても同じである。シリアライズされる際のコンストラクタの呼ばれ方は通常の呼ばれ方と異なることがわかる。

コンソール

コンソールが利用可能な端末ではSystem.consoleでコンソールを取得できる。組み込みの実行環境であれば当然コンソールは存在しないためnullが返却される。

import java.io.Console;
import java.io.PrintWriter;

public class ConsoleTry {
    public static void main(String[] args){
        Console console = System.console();
        String str = console.readLine();

        PrintWriter writer = console.writer();
        writer.append("Input : " + str);
        writer.flush();//'Input : hello'

        char[] writer2 = console.readPassword();
        writer.append("PW: " + writer2);
        writer.flush();
    }

    }
}