JAVA X2 type02　Season1 Chapter4：さて、書いてみましょうか（震）

02、はじめてのコーディング

まずは基本的動作を知るために師匠からの課題

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/d01b81c4-69ad-93f3-0aad-99e34e8e4b29.png)

# JVMの外のリソース（ファイル、ネットワークなど）を使うには

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/eb05259b-16a7-aa27-3258-883c4c033790.png)

まず、JVM(Java Virtual Machine)のヒープ上にファイルオブジェクトを置く。
でもね、このオブジェクトはファイルそのものではない。
ファイルを**扱うための機能**なんだ。

ここで質問です。
実際のファイルは **JVMにあるの？** ないの？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/dd742df7-63d5-eecc-5765-300ce3928c8f.png)
※クイズ形式の問答大嫌いなおつう。

（おつうの考え）
Javaって「ファイルに書いて」て命令なかったら（仮）みたいな状況なんじゃないの？
つまり書き込む準備はしてもファイルに「書き込む」は別に命令しなくちゃならない認識ですが間違ってますか（イライラ）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/afc40a16-1113-3211-22cc-5e80ced47e05.png)

(マスター)
考えのベクトルはあっていると思う。ファイルシステムはOSの機能だから。ファイルもOSが管理している。つまりJVMの中いわゆる、誰もが見える形の「ファイル」はなくて、**OS=Virtual Machineの外のリソース** を使いたいってことになるんだ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/abd7a90c-bf17-a508-8d85-5b3d8d3b679f.png)
(マスター)
Javaでは、JVMの外のリソースとデータのやり取りをするとき、OutputStream/InputStreamを使って行うことになる。InputStreamはJVMの外からVMにデータを引き込む＝参照ために使い、反対にOutputStreamはJVMからリソースに向かってデータを出す＝書き出しのために使うんだ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/191a0f1f-8396-d92d-fefb-e5b26ab0cec6.png)

（おつう）
こういうことですね

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/21fb3142-4375-5f76-b378-453fbf68a8df.png)（図1.1）

図1.1の認識で問題ないとのことなので（苛々）、ここから実際にコードにしていきます。

# 「FileOutputStream」を使う

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/a7b28fc6-5666-4ac8-8f18-a8b0e3cd1848.png)

なんで師匠が敬語なのかは置いといて。今日の本題に移ります。

今回は、「ファイルの書き出しをやるので」FileOutputStreamを使ってみましょう。

前回使用した、MAVEN様が自動で作成した「Hello World!」をプロンプトに表示するだけのコードを再利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/e09270b3-30f8-c1ad-ec61-1b039e42cdc8.png)

今回、大まかな手順は以下の通りです。

1. JVMのヒープ上にFileオブジェクトを生成する
1. FileOutputStreamを開く
1. データを書き込む

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/11051b64-95d8-f6fe-f638-dc8186873d2e.png)

# コーディングします

まず、このHello Worldしてる行は不要なので、いったんコメントアウトします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/7be78138-bc5a-63c0-e1f8-5f84abf4258d.png)

他の場所はそのまま使えるのでmainだけいじくります。
（動作知りたいだけなので、他の場所の詳細は後日）

## ①Fileオブジェクトを作る

mainに以下の通り書きます。

```Java

    public static void main(String[] args) {
        File myFile = new File("Hello.txt");
    }

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/9dd0cc05-06a8-329a-f992-4ae294d105a1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/25a44dac-20a9-132f-50e5-26318c8da506.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/6f33b549-48ec-9b42-ec13-a3d03972263c.png)



（マスター）
[1] は変数の「型」の宣言＝今後このmyFileをどの機能(=クラス)として扱うかの宣言だよ。コンパイラは今後、型チェックが必要な場面で、この変数を「File型」として取り扱ってくれる。
[2]は実際にヒープ上に乗せる機能の型だよ。いまは[1] = [2]でいいけど、勉強が進んでいくとこの二つが違う場面が出てくるよ。そして、割とそれが重要になる。(オブジェクト指向的な要素の解説は後回しなので、今後登場する予定)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/27317b3e-ce05-2a8f-4caf-257f1c941228.png)

（マスター）
そういうこと。本来違う意味のものなので個別に宣言しないといけないよ。

## ②FileOutputStreamを作る

```Java
public static void main(String[] args) {
        File myFile = new File("Hello.txt");
        FileOutputStream outPutStream = new FileOutputStream(myFile);
}
```

（おつう）
①では、変数「myfile」にファイルオブジェクトの参照を格納する。ここまでやりました。
次は、変数「myfile」をつかって新たにFileOutputStreamを作る・・？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/49a05997-25ec-37a4-7321-a930aaf4b66b.png)

（おつう）
これ、ストレージ側にはなにもないよね。ないものに対してつないでる？？？
どういうこと？？
ファイルもないし書いてもないじゃん。意味わからない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/b002fe6e-d1b1-a31e-b643-ddfaa8f0679c.png)

（マスター）
ここでは、FileOutputStreamはFileオブジェクトとVMの外の実際のファイルとつないで書き込みの **「準備」** だけする。
- 実際にストレージ上にファイルがあるか確認する
- ファイルがあるなら(今回は上書きモードで)開く
- ファイルがないならファイルを作る

ここまでのことをやって、書き込みの **「準備」** をする。実際に書き込むのはこの後だよ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/04d6fe50-1dbb-16d6-d786-6836d917bdbc.png)

# ③FileOutputStreamを使って。Storageに書き込む

```Java
public static void main(String[] args) {
        //System.out.println("Hello World!");
        File myFile = new File("Hello.txt");
        FileOutputStream outPutStream = new FileOutputStream(myFile);
        byte[] fileData = {97, 98, 99, 100};
        outPutStream.write(fileData);
    }
```

byte型配列にデータを用意して(fileData)、OutputStreamでかき出す＝write
しました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/0417a4a1-8865-29f3-3824-580cde7ca2e4.png)

なんか意味わからんエラーが。。。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/ec8f8295-b0e1-9796-a495-8a2abad49bd1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/2774c4e8-ecee-eb3e-21a6-ad8f85f22564.png)

（マスター）
うん。今まで黙ってたけど。Javaは利用するメソッドで何らかのエラーが発生する可能性がある場合。それを例外としてユーザープログラマに通知することがあることをメソッドで宣言しているんだね。そしてユーザープログラマは、その例外を適切に処理する**責務を負っている。** ここでは、FileOuputStreamの生成時に「つなぎ先のファイルがないかもしれない=FileNotFoundException」エラーが想定される。また、outPutStream.write(data)を使っているときには、「例えばストレージに空き容量がなくて書き込めない=IOException」を想定してくれている。だから書く側がこれを「適切に」処理しなくちゃいけない。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/45bd65fc-4523-9470-4729-9cdc4f0faba9.png)

# 例外処理の追加

赤い波線（compile error）をクリックした後の電球マークをクリックすると、出てくる選択の中の「Add throws declaration」-> これは丸投げだからわからないうちは使わないほうがいいやつ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/b60e1708-f29a-f7c4-a202-9bd569b74e37.png)

こちらを使います。（本命は真ん中だけど、今後別途説明）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/dde1530c-c94d-9d76-02ff-f5b86654abb3.png)

```java
 public static void main(String[] args) {
        //System.out.println("Hello World!");
        File myFile = new File("Hello.txt");
        FileOutputStream outPutStream;
        try {
            outPutStream = new FileOutputStream(myFile);
            byte[] fileData = {97, 98, 99, 100};
            outPutStream.write(fileData);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/c80f45ab-8064-fb1f-55cc-cb7ef8155290.png)

ここでは、捕まえたあとはStackTraceを表示するだけ。
StackTrace:例外発生時の命令呼び出し及びエラー原因が入っている情報

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/cc122b56-1e7f-bc2c-dca6-b9f66e7431cb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/382a1be2-b213-9ba0-b670-ebe7cfa24625.png)



# Hello.txt できた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/f9b1be73-34e4-72b8-eb0a-c16e0b65867b.png)


終了。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2308477/344bb625-c6c6-afed-ce2a-ea969ecd1015.png)



## まとめ
配列で用意して文字列をファイルに書き込みました。でも実際こんなのやります？やらないよね。
不満たらたらで文句言ったら「次回教えるから待って？」とのこと。
とりあえずファイル書き込みはこうやるんだよは呑み込めたのでよしとして。
**仕方ないから！！** 次回待ちます！！（すすまねぇ！！！）

＞＞次回「データの配列じゃなくて文字列で書き込みしたいんすけど」をお送りします。