Android'de bir dosyanın kopyası nasıl oluşturulur?


178

Uygulamamda, belirli bir dosyanın farklı bir adla (kullanıcıdan aldığım) bir kopyasını kaydetmek istiyorum

Gerçekten dosyanın içeriğini açıp başka bir dosyaya yazmam gerekiyor mu?

Bunu yapmanın en iyi yolu nedir?


Java7 öncesi, bence cevap evet. stackoverflow.com/questions/106770/… .
Paul Grime


Yaşlı kontrol yazı
Deepak

Yanıtlar:


327

Bir dosyayı kopyalayıp hedef yolunuza kaydetmek için aşağıdaki yöntemi kullanabilirsiniz.

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+ sürümünde Java Otomatik Kaynak Yönetimi'ni kullanabilirsiniz:

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
Teşekkür ederim. kafamı vurduktan sonra sorunun harici depolama birimine yazma izninin eksik olduğunu gördüm. şimdi iyi çalışıyor.
AS

8
@ mohitum007 dosya kopyalanamazsa bir istisna atılır. yöntemi çağırırken bir try catch bloğu kullanın.
Nima G

9
Bir istisna atılırsa, akışlar çöp toplanana kadar kapatılmaz ve bu iyi değildir . Onları kapatmayı düşünün finally.
Pang

1
@Pang. Haklısın. Daha da kötüsü, in / out.close () çağrılmalıdır, aksi takdirde GC açık dosya tanımlayıcılarını asla kapatmayacağından temel işletim sisteminde bir kaynak kaçağı olacaktır. GC, JVM dışındaki dosya kaynaklarını, dosya tanımlayıcılar veya soketler gibi kapatamaz. Bunlar her zaman nihayet bir maddede programlı olarak kapatılmalı veya yeni denemeye kaynak kullan yeni sözdizimi kullanılmalıdır: docs.oracle.com/javase/tutorial/essential/exceptions/…
earizon

4
Lütfen, son olarak her iki Akışı da kapatın, bir İstisna varsa, akış belleğiniz toplanmaz.
pozuelog

121

Alternatif olarak, bir dosyayı kopyalamak için FileChannel'i kullanabilirsiniz . O olabilir büyük bir dosya kopyalarken hızlı bayt kopyalama yönteminden daha olacak. Dosyanız 2 GB'den büyükse kullanamazsınız.

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
Bir istisna atabilir ve bu durumda akışları açık bırakırsınız. Tıpkı Pang ve Nima'nın kabul edilen cevapta yorumladığı gibi.
Viktor Brešan

Ayrıca, transferTo, istenen toplam miktarı transfer edeceğini garanti etmediğinden, döngü içinde çağrılmalıdır.
Viktor Brešan

Çözümünüzü denedim java.io.FileNotFoundException: /sdcard/AppProj/IMG_20150626_214946.jpg: open failed: ENOENT (No such file or directory)ve FileOutputStream outStream = new FileOutputStream(dst);adımdaki istisna dışında benim için başarısız oldu . Anladığım metne göre, dosyanın mevcut olmadığını, bu yüzden dosyayı kontrol edip dst.mkdir();gerekirse ararım , ancak yine de yardımcı olmaz. Ayrıca kontrol etmeye çalıştı dst.canWrite();ve döndü false. Sorunun kaynağı bu olabilir mi? Ve evet, var <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>.
Mike

1
@ ViktorBrešan API 19'dan sonra, denemenizin açılışında giriş ve çıkış akışlarını tanımlayarak Java otomatik kaynak yönetimini kullanabilirsiniztry ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {
AlbertMarkovski

Bu çözümü onProgressUpdatebir ProgressBar'da gösterebilmem için ilerlemesini yayınlamanın herhangi bir yolu var mı ? Kabul edilen çözümde while döngüsündeki ilerlemeyi hesaplayabilirim, ancak burada nasıl yapılacağını göremiyorum.
George Bezerra

31

Bunun için Kotlin uzantısı

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

Bu en kısa ve esnek cevaptır. Daha basit yanıtlar, üzerinden açılan URI'ları hesaba katmaz contentResolver.openInputStream(uri).
AjahnCharles

6
Kotlin aşktır, Kotlin hayattır!
Dev Aggarwal

17

Bunlar benim için iyi çalıştı

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

Bu, Android O'da (API 26) basittir, gördüğünüz gibi:

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

10

Bir cevap için çok geç olabilir ama en uygun yol

FileUtils'ler

static void copyFile(File srcFile, File destFile)

örneğin benim yaptığım bu

'

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'de yerel olarak mevcut değil.
Berga

2
Ancak Apache tarafından yapılan ve bunu yapan bir kütüphane var: commons.apache.org/proper/commons-io/javadocs/api-2.5/org/…
Alessandro Muzzi

7

Kotlin ile şimdi çok daha basit:

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

trueveya falsehedef dosyanın üzerine yazmak içindir

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


Dosyanız Galeri amacı Uri'den geliyorsa o kadar basit değil.
AjahnCharles

Aşağıdaki yanıtı okuyun: "Bu yanıt aktif olarak zararlıdır ve aldığı oyları hak etmiyor. Uri bir içerik: // veya başka bir dosya olmayan Uri ise başarısız olur." (Ben oy verdim - sadece bir gümüş mermi olmadığını açıklamak istedim)
AjahnCharles

5

Kopyalama sırasında bir hata oluşursa giriş / çıkış akışlarını gerçekten kapatan bir çözüm. Bu çözüm, akışların hem kopyalanması hem de kapatılması için apache Commons IO IOUtils yöntemlerini kullanır.

    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);
        }
    }

Basit görünüyor
Serg Burlaka

2

kotlin'de, sadece:

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

fileSrc.copyTo(fileDest)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.