＊Android＊内部ストレージへのファイルの保存・読み込み

#はじめに
こんにちは．今日から記事を書き始めます．
プログラミングのメモとしてQiitaを活用していくつもりです．
私は，Androidを使い始めて2年程になります．来年から就職する大学院生です．

今回は，Androidの内部ストレージへのファイルの保存・読み込みについて解説します．Androidのストレージに関する解説に関する記事は，どれも内容が少しずつ異なり，迷ってしまう方もいると思うので，標準的なものを書きます．

#前提
開発環境は以下の通りです．
＊Android Studio 4.0.1
＊targetSdkVersion 28
＊Google Nexus 5x

#内部ストレージと外部ストレージ
Androidには，内部ストレージと外部ストレージが存在します．

■内部ストレージ 

* 常に利用できる
* ファイルへのアクセスは，保存元のアプリからしかできない．
* ユーザがアプリをアンインストールすると，ファイルは自動的に内部ストレージから削除される．

■外部ストレージ

* マウントされていることを確認してから使用する必要がある．
* ファイルへのアクセスに制限はない．

保存に使用するストレージは以下の3つがある．

* 内部ストレージ
* 外部ストレージのアプリ固有の領域
* 外部ストレージの共有ファイルの領域

各ストレージは，Android StudioのDevice File Explorerの構造では以下に保存されます．

* 内部ストレージ　/data/data/パッケージ名/files/
* 外部ストレージのアプリ固有の領域　/sdcard/Android/data/パッケージ名/files/
* 外部ストレージの共有ファイルの領域　/sdcard/

# ファイルを内部ストレージに保存する
ファイル保存では ```FileOutputStream``` のインスタンスを ```openFileOutput()``` メソッドを使用して取得します．これによりストリームを開くことができます．また，```openFileOutput()```を使用すると，内部ストレージのパスを指定しなくても，自動的にパスを取得して保存してくれます．

```java
FileOutputStream fileOutputstream = openFileOutput("text.txt", Context.MODE_PRIVATE);
```

**第1引数**
```"/パス/ファイル名"```

**第2引数**

| 値|説明|
|:--|:--|
|MODE_WORLD_READABLE   |他のアプリから参照可能     |
|MODE_WORLD_WRITEABLE  |他のアプリから書き込み可   |
|MODE_PRIVATE          |他のアプリからアクセス不可 |
|MODE_APPEND           |ファイルがあると，追記     |


また、モードを複数指定する場合にはパイプを繋げると複数指定できます。
```MODE_PRIVATE | MODE_APPEND```

あとは，ファイルに書き出したい文字列をbyte型の配列に変換し， ```write()``` を使ってストリームに書き出します．

```java
fileOutputStream.write(str.getBytes());
```
# ファイルをストレージから読み込む
ファイルの読み込みでは ```FileInputStream``` のインスタンスを ```openFileInput()``` メソッドを使用して取得します．これにより，ストリームを開くことができます．

```java
FileInputStream fileInputStream = openFileInput("text.txt");
```

```InputStreamReader``` でストリームからバイトを読み込み、指定された文字にデコードします．それを```BufferedReader``` に入れて、行毎に読み出します。変換効率を上げるため、```BufferedReader``` の内部に ```InputStreamReader``` をラップするのがいいようです。

```java
BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"));
String lineBuffer;
while (true){
    lineBuffer = reader.readLine();
    if (lineBuffer != null){
        text += lineBuffer;
    }
    else {
        break;
    }
}
```

#サンプルコード
activity_main.xml

```java
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="50dp"
        android:layout_marginTop="100dp"
        android:text="Save File"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="100dp"
        android:layout_marginTop="100dp"
        android:text="Read File"
        app:layout_constraintStart_toEndOf="@+id/button1"
        app:layout_constraintTop_toTopOf="parent" />
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="120dp"
        android:text=""
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText" />
    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:ems="10"
        android:inputType="textPersonName"
        android:text="Name"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
```

MainActivity.java

```java
package com.example.keita.myapplication;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class MainActivity extends AppCompatActivity {
    private TextView textView;
    private Button button1;
    private Button button2;
    private EditText editText;
    private String fileName = "test.txt";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.textView = findViewById(R.id.textView);
        this.editText = findViewById(R.id.editText);
        this.button1 = findViewById(R.id.button1);
        this.button2 = findViewById(R.id.button2);
        this.button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String text = editText.getText().toString();
                saveFile(fileName, text);
            }
        });
        this.button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String str = readFile(fileName);
                textView.setText(str);
            }
        });
    }


    private void saveFile(String file, String str){
        try {
            FileOutputStream fileOutputStream = openFileOutput(file, MODE_PRIVATE | MODE_APPEND);
            fileOutputStream.write(str.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private String readFile(String file){
        String text = null;
        try {
            FileInputStream fileInputStream = openFileInput(file);
            BufferedReader reader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"));
            String lineBuffer;
            while (true){
                lineBuffer = reader.readLine();
                if (lineBuffer != null){
                    text += lineBuffer;
                }
                else {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return text;
    }
}
```