Androidでファイルのコピーを作成するにはどうすればよいですか?


178

私のアプリでは、特定のファイルのコピーを別の名前で保存したい(ユーザーから取得したもの)

ファイルの内容を開いて別のファイルに書き込む必要がありますか?

そうするための最良の方法は何ですか?


Java7以前では、答えは「はい」です。 stackoverflow.com/questions/106770/…
Paul Grime


回答:


327

ファイルをコピーして宛先パスに保存するには、以下の方法を使用できます。

public static void copy(File src, File dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        } finally {
            out.close();
        }
    } finally {
        in.close();
    }
}

API 19以降では、Java自動リソース管理を使用できます。

public static void copy(File src, File dst) throws IOException {
    try (InputStream in = new FileInputStream(src)) {
        try (OutputStream out = new FileOutputStream(dst)) {
            // Transfer bytes from in to out
            byte[] buf = new byte[1024];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }
        }
    }
}

8
ありがとうございました。頭を叩いた後、問題は外部ストレージへの書き込み権限がないことがわかりました。今では正常に動作します。
AS

8
@ mohitum007ファイルのコピーに失敗すると、例外がスローされます。メソッドを呼び出すときにtry catchブロックを使用します。
Nima G

9
例外がスローされた場合、ストリームはガベージコレクションされるまで閉じられませんこれは適切ではありません。それらをで閉じることを検討してくださいfinally
2014

1
@Pang。あなたが正しいです。さらに悪いことに、GCは開いているファイル記述子を決して閉じないため、in / out.close()を呼び出す必要があります。そうしないと、基になるOSでリソースリークが発生します。GCは、ファイル記述子やソケットなど、JVMの外部のOSリソースを閉じることができません。:これらは、常にfinally節では、プログラムで、または使用のtry-とリソースの新しい構文閉じなければならないdocs.oracle.com/javase/tutorial/essential/exceptions/...を
earizon

4
最後に両方のストリームを閉じてください。Excepcionがある場合、ストリームメモリは収集されません。
pozuelog 2016

121

または、FileChannelを使用してファイルをコピーすることもできます。それは可能性が大きいファイルをコピーする際に高速バイトのコピー方法よりも。ただし、ファイルが2GBより大きい場合は使用できません。

public void copy(File src, File dst) throws IOException {
    FileInputStream inStream = new FileInputStream(src);
    FileOutputStream outStream = new FileOutputStream(dst);
    FileChannel inChannel = inStream.getChannel();
    FileChannel outChannel = outStream.getChannel();
    inChannel.transferTo(0, inChannel.size(), outChannel);
    inStream.close();
    outStream.close();
}

3
transferToは例外をスローする可能性があり、その場合はストリームを開いたままにします。ちょうどパンとニマが受け入れられた答えでコメントしたように。
ViktorBrešan2014年

また、transferToは、要求された合計量を転送することを保証しないため、ループ内で呼び出す必要があります。
ViktorBrešan2014年

私はあなたの解決策を試しjava.io.FileNotFoundException: /sdcard/AppProj/IMG_20150626_214946.jpg: open failed: ENOENT (No such file or directory)ましたが、FileOutputStream outStream = new FileOutputStream(dst);ステップでの例外を除いてそれは私のために失敗します。私が気づいたテキストによると、ファイルは存在しないので、それをチェックして、dst.mkdir();必要に応じて呼び出しますが、それでもまだ役に立ちません。私もチェックdst.canWrite();してみましたが、戻ってきましたfalse。これが問題の原因ですか?そして、はい、私は持ってい<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>ます。
マイクB.

1
@ViktorBrešanAPI 19の後、トライの開始時にインストリームとアウトストリームを定義することにより、Java自動リソース管理を使用できますtry ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {
AlbertMarkovski

このソリューションに進捗状況をonProgressUpdateに公開させる方法はありますか?それで、ProgressBarでそれを示すことができますか?受け入れられたソリューションでは、whileループで進行状況を計算できますが、ここではその方法を確認できません。
ジョージBezerra

31

Kotlin拡張機能

fun File.copyTo(file: File) {
    inputStream().use { input ->
        file.outputStream().use { output ->
            input.copyTo(output)
        }
    }
}

これは最も簡潔かつ柔軟な答えです。より単純な回答では、を介して開かれたURIを考慮できませんcontentResolver.openInputStream(uri)
AjahnCharles

6
コトリンは愛であり、コトリンは人生です!
Dev Aggarwal

17

これらは私にとってうまくいった

public static void copyFileOrDirectory(String srcDir, String dstDir) {

    try {
        File src = new File(srcDir);
        File dst = new File(dstDir, src.getName());

        if (src.isDirectory()) {

            String files[] = src.list();
            int filesLength = files.length;
            for (int i = 0; i < filesLength; i++) {
                String src1 = (new File(src, files[i]).getPath());
                String dst1 = dst.getPath();
                copyFileOrDirectory(src1, dst1);

            }
        } else {
            copyFile(src, dst);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public static void copyFile(File sourceFile, File destFile) throws IOException {
    if (!destFile.getParentFile().exists())
        destFile.getParentFile().mkdirs();

    if (!destFile.exists()) {
        destFile.createNewFile();
    }

    FileChannel source = null;
    FileChannel destination = null;

    try {
        source = new FileInputStream(sourceFile).getChannel();
        destination = new FileOutputStream(destFile).getChannel();
        destination.transferFrom(source, 0, source.size());
    } finally {
        if (source != null) {
            source.close();
        }
        if (destination != null) {
            destination.close();
        }
    }
}

13

これはAndroid O(API 26)では簡単です。

  @RequiresApi(api = Build.VERSION_CODES.O)
  public static void copy(File origin, File dest) throws IOException {
    Files.copy(origin.toPath(), dest.toPath());
  }

10

答えには遅すぎるかもしれませんが、最も便利な方法は

FileUtils

static void copyFile(File srcFile, File destFile)

例えばこれは私がやったことです

`

private String copy(String original, int copyNumber){
    String copy_path = path + "_copy" + copyNumber;
        try {
            FileUtils.copyFile(new File(path), new File(copy_path));
            return copy_path;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

`


20
FileUtilsは、Androidにはネイティブには存在しません。
ベルガ

2
しかし、これ以上のことを行う、Apacheによって作成されたライブラリがあります。commons.apache.org
Alessandro Muzzi

7

Kotlinを使用すると、はるかに簡単になります。

 File("originalFileDir", "originalFile.name")
            .copyTo(File("newFileDir", "newFile.name"), true)

trueまたはfalse宛先ファイルを上書きするためのものです

https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.io/java.io.-file/copy-to.html


ファイルがギャラリーインテントUriからのものである場合、それほど単純ではありません。
AjahnCharles

その回答の下にあるコメントをお読みください:「この回答は積極的に有害であり、投票に値するものではありません。URIがcontent://またはその他の非ファイルURIである場合、失敗します。」(
賛成票を投じました

5

これは、コピー中にエラーが発生した場合に実際に入出力ストリームを閉じるソリューションです。このソリューションは、ストリームのクローズのコピーと処理の両方にApache Commons IO IOUtilsメソッドを利用します。

    public void copyFile(File src, File dst)  {
        InputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(src);
            out = new FileOutputStream(dst);
            IOUtils.copy(in, out);
        } catch (IOException ioe) {
            Log.e(LOGTAG, "IOException occurred.", ioe);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(in);
        }
    }

シンプルに見える
Serg Burlaka

2

コトリンでは、ちょうど:

val fileSrc : File = File("srcPath")
val fileDest : File = File("destPath")

fileSrc.copyTo(fileDest)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.