質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.77%

androidで内部ストレージからSDカードへのファイルコピーがうまくいかない

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,543

luckyclock

score 63

下記のメソッドを利用して内部ストレージにあるファイルをSDカードへ
コピーしようとしているのですが、うまくいきません。
普通に実行するとSDカードにファイルは作成されるのですが、中身がコピーされません。
メソッドの先頭にブレークをはってステップ実行していくとなぜかうまく中身も
コピーされます。
まったくもって原因がわかりません。
コードに何か問題あるでしょうか?

追記

検索していたらFileOutputStreamのflushについて下記のような説明を発見しました。

このストリームの目的の転送先が、基本となるオペレーティングシステムによって提供される抽象化オブジェクト (ファイルなど) である場合、ストリームをフラッシュすることで、それまでにストリームに書き込まれたバイトがオペレーティングシステムに渡されて書き込まれることは保証されますが、ディスクドライブなどの物理デバイスに実際に書き込まれることは保証されません。 

物理デバイスに書き込まれることは保証されないとあります。
もしかしてこれが原因?
だとしてどのように変更すればよいのでしょうか?
保証されるメソッドがある?

    private boolean copy2ExternalStorage(String sdpath, String filename) {
        // 現在ストレージが書き込みできるかチェック
        String state = Environment.getExternalStorageState();

        if (state.equals(Environment.MEDIA_MOUNTED)) {
            try (FileInputStream fileInputStream = openFileInput(filename)) {
                String path = sdpath + "/" + filename;
                File file = new File(path);
                try (FileOutputStream fileOutputStream = new FileOutputStream(file, false)) {   //追加書き込みしない
                    byte[] buf = new byte[256];
                    int len;
                    while((len = fileInputStream.read(buf)) != -1){
                        fileOutputStream.write(buf, 0, len);
                    }
                    fileOutputStream.flush();
                    fileOutputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                    return false;
                }
                fileInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
            Toast.makeText(this, "コピー完了", Toast.LENGTH_LONG).show();
        }
        else if(state.equals(Environment.MEDIA_MOUNTED_READ_ONLY)){
            Toast.makeText(this, "このSDカードは読取専用です。", Toast.LENGTH_LONG).show();
            return false;
        }
        else if(state.equals(Environment.MEDIA_REMOVED)){
            Toast.makeText(this, "SDカードが挿入されていません。", Toast.LENGTH_LONG).show();
            return false;
        }
        else if(state.equals(Environment.MEDIA_UNMOUNTED)){
            Toast.makeText(this, "SDカードがマウントされていません。", Toast.LENGTH_LONG).show();
            return false;
        }
        else{
            Toast.makeText(this, "SDカードを確認してください。", Toast.LENGTH_LONG).show();
            return false;
        }
        return true;
    }

copy2ExternalStorageを呼び出すメソッド。
テスト端末ではBuild.VERSION.SDK_INTが23未満なのでcheckPermissionは実行
しない

    public void onClickSd(View view) {
        new AlertDialog.Builder(this)
                .setTitle("データ保存")
                .setMessage("外部SDカードに保存しますか?\n※同名のファイルがある場合上書きされます")
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // TODO 自動生成されたメソッド・スタブ
                        // Android 6, API 23以上でパーミッシンの確認
                        if (Build.VERSION.SDK_INT >= 23) {
                            checkPermission();
                        } else {
                            List<String> path = getSdCardFilesDirPathListForLollipop(getApplicationContext());
                            if(path.size()  >= 1) {    //外部ストレージが見つかった
                                for(int i = 0; i < listItems.size(); i++) {
                                    if (copy2ExternalStorage(path.get(path.size() - 1), listItems.get(i).getName())){
                                    }
                                }
                            }
                            else {
                                Toast.makeText(getApplicationContext(), "コピーできませんでした", Toast.LENGTH_LONG).show();
                            }
                        }
                    }
                })
                .setNegativeButton("No", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // TODO 自動生成されたメソッド・スタブ
                    }
                })
                .show();
    }
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • luckyclock

    2018/03/30 17:45

    リードというのはFileOutputStreamの内部ストレージのデータのことですね。書き込めない時はファイルのみ生成されてファイルの中身が空ですが、空のデータをライトしているわけではないということです。OSバージョンは5.1.1です。

    キャンセル

  • aja

    2018/03/30 19:28

    「書き込めない時は」というのは書き込める時もあるという事でしょうか。SAFを使ってますか?としか言いようがないのですが

    キャンセル

  • luckyclock

    2018/04/02 10:19

    書き込めることもあります。書き込めないことの方が多いような気がしますが。SAFとはなんのことかよくわかりませんが、少し調べてみます。

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.77%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る