214

In my app I want to save a copy of a certain file with a different name (which I get from user)

Do I really need to open the contents of the file and write it to another file?

What is the best way to do so?

SBerg413
  • 14,515
  • 6
  • 62
  • 88
A S
  • 2,924
  • 5
  • 22
  • 27

12 Answers12

361

To copy a file and save it to your destination path you can use the method below.

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

On API 19+ you can use Java Automatic Resource Management:

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);
            }
        }
    }
}
Thomas Vos
  • 12,271
  • 5
  • 33
  • 71
Rakshi
  • 6,796
  • 3
  • 25
  • 46
  • 8
    Thank you. after banging my head I found the problem was missing permission to write to external storage. now it works fine. – A S Feb 16 '12 at 09:51
  • can you tell me how to check in this code that the file is successfully copied or not? – mohitum Mar 22 '13 at 09:37
  • 8
    @mohitum007 if the file fails to copy then an exception is thrown. use a try catch block when calling the method. – Nima Apr 15 '13 at 10:20
  • 10
    If an exception is thrown, the streams would not be closed until they're garbage collected, and [that's not good](http://stackoverflow.com/questions/515975/closing-streams-in-java#comment5185168_515981). Consider closing them in `finally`. – Pang Apr 18 '14 at 10:14
  • 1
    @Pang. You are right. What's worse, in/out.close() must be called or otherwise there will be a resource leakage in the underlying OS, since the GC will never close the open file descriptors. GC can't close OS resources external to the JVM like file-descriptors or sockets. Those must always be closed in a finally clause programatically or use try-with-resource new syntax: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html – earizon Jul 18 '15 at 17:27
  • Does this overwrite the duplicate if there is one? – mc9 Nov 11 '15 at 03:40
  • 4
    Please, close both Streams inside a finally, if there is an Excepcion, your streams memory won't be collected. – pozuelog Feb 19 '16 at 11:55
  • @Rakhi when i copy large size file it is taking time so can you tell me what should i do for fast copy in one folder to another thanks – Pradeep Bishnoi Feb 26 '16 at 07:42
  • @pradeepbishnoi you can try to use larger buffer: byte[] buf = new byte[choose_large_value]; – Meet Vora Aug 13 '16 at 06:43
  • 1
    After API 19 you can use Java automatic resource management by defining the in and out streams in the opening of your try `try ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {` – AlbertMarkovski Oct 05 '16 at 16:43
  • Like others I'm down voting due to the lack of closing streams. Also in Java 8 you can use Files.copy -- https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#copy-java.nio.file.Path-java.nio.file.Path-java.nio.file.CopyOption...- – adamfisk Mar 08 '17 at 04:55
  • 1
    @adamfisk java.nio.file is not yet in any version of the Android API. – mhsmith Mar 16 '17 at 20:33
  • Yeah good point @mhsmith -- I realized that just after commenting. Files.copy is also available in Java 7 actually, but alas not on Android. – adamfisk Mar 17 '17 at 21:21
  • [`Files.copy` **is** available](https://developer.android.com/reference/java/nio/file/Files#copy(java.nio.file.Path,%252520java.nio.file.Path,%252520java.nio.file.CopyOption...)) as of API Level 26. – phihag Jul 25 '19 at 14:50
  • Hello. I used the first "copy()" method you suggested. Right after obtaining the file copy, on the Android mobile, if I chose "Use USB for File transfers", I can't see the file from the PC. If I reboot the Android mobile and select "Use USB for File transfers", I can see the file from the PC. What is going wrong with that way of creating a file on the Android mobile? Thanks. – Léa Massiot Jun 09 '20 at 18:07
  • 1
    ` > 0` is bug. Sometimes it is possible to have read return 0 bytes and then the write with 0 bytes can throw an exception. It's better to check for `!= -1` – Ilya Gazman Nov 26 '20 at 22:35
137

Alternatively, you can use FileChannel to copy a file. It might be faster than the byte copy method when copying a large file. You can't use it if your file is bigger than 2GB though.

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();
}
NullNoname
  • 2,056
  • 1
  • 15
  • 12
  • 3
    transferTo can throw an exception and in that case you are leaving streams open. Just like Pang and Nima commented in accepted answer. – Viktor Brešan Nov 29 '14 at 05:42
  • Also, transferTo should be called inside of loop since it does not guarantee that it will transfer the total amount requested. – Viktor Brešan Nov 29 '14 at 05:43
  • I tried your solution and it fails for me with the exception `java.io.FileNotFoundException: /sdcard/AppProj/IMG_20150626_214946.jpg: open failed: ENOENT (No such file or directory)` at the `FileOutputStream outStream = new FileOutputStream(dst);` step. According to the text I realize, that the file doesn't exist, so I check it and call `dst.mkdir();` if needed, but it still doesn't help. I also tried to check `dst.canWrite();` and it returned `false`. May this is the source of the problem? And yes, I have ``. – Mike Jun 26 '15 at 19:00
  • 1
    @ViktorBrešan After API 19 you can use Java automatic resource management by defining the in and out streams in the opening of your try `try ( FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst) ) {` – AlbertMarkovski Oct 05 '16 at 16:44
  • 1
    Is there any way to make this solution publish its progress to `onProgressUpdate`, so I could show it in a ProgressBar? In the accepted solution I can calculate progress in the while loop, but I can't see how to do it here. – George Bezerra Feb 22 '17 at 13:39
  • @MikeB. If you're running it on API 23 or above, try checking for the runtime permission. – Ariq Sep 15 '17 at 10:27
  • even better with try with resources --> try (FileInputStream inStream = new FileInputStream(src); FileOutputStream outStream = new FileOutputStream(dst)) – Alireza Jamali Aug 30 '20 at 14:37
64

Kotlin extension for it

fun File.copyTo(file: File) {
    inputStream().use { input ->
        file.outputStream().use { output ->
            input.copyTo(output)
        }
    }
}
Dmytro Rostopira
  • 10,588
  • 4
  • 64
  • 86
22

This is simple on Android O (API 26), As you see:

  @RequiresApi(api = Build.VERSION_CODES.O)
  public static void copy(File origin, File dest) throws IOException {
    Files.copy(origin.toPath(), dest.toPath());
  }
Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
LeeR
  • 568
  • 6
  • 10
20

These worked nice for me

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();
        }
    }
}
Bojan Kseneman
  • 15,488
  • 2
  • 54
  • 59
19

Much simpler now with Kotlin:

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

trueorfalse is for overwriting the destination file

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

Johann
  • 27,536
  • 39
  • 165
  • 279
Blundell
  • 75,855
  • 30
  • 208
  • 233
  • Not so simple if your File comes from a Gallery intent Uri. – charles-allen Jan 18 '19 at 05:55
  • Read the comments below that answer: "This answer is actively harmful and does not deserve the votes it get. It fails if the Uri is a content:// or any other non-file Uri." (I did upvote - I just wanted to clarify it's not a silver-bullet) – charles-allen Jan 18 '19 at 09:46
11

It might be too late for an answer but the most convenient way is using

FileUtils's

static void copyFile(File srcFile, File destFile)

e.g. this is what I did

`

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

`

stopBugs
  • 351
  • 3
  • 10
  • 26
    FileUtils does not exist natively in Android. – The Berga May 02 '16 at 08:30
  • 2
    But there's a library made by Apache that do this and more: https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/FileUtils.html – Alessandro Muzzi Dec 09 '16 at 15:21
  • @TheBerga Could you elaborate? I found these copy methods, but can't use them. The comments of these methods claim that there's some optimization, so I'm tempted to use. – Minh Nghĩa May 15 '21 at 19:44
  • I think Fileutils requires inputstream https://developer.android.com/reference/android/os/FileUtils – CrackerKSR Jul 19 '22 at 15:30
8

in kotlin , just :

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

fileSrc.copyTo(fileDest)
Sodino
  • 587
  • 6
  • 16
5

Here is a solution that actually closes the input/output streams if an error occurs while copying. This solution utilizes apache Commons IO IOUtils methods for both copying and handling the closing of streams.

    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);
        }
    }
SBerg413
  • 14,515
  • 6
  • 62
  • 88
1

in Kotlin: a short way

// fromPath : Path the file you want to copy 
// toPath :   The path where you want to save the file
// fileName : name of the file that you want to copy
// newFileName: New name for the copied file (you can put the fileName too instead of put a new name)    

val toPathF = File(toPath)
if (!toPathF.exists()) {
   path.mkdir()
}

File(fromPath, fileName).copyTo(File(toPath, fileName), replace)

this is work for any file like images and videos

Ramin eghbalian
  • 2,348
  • 1
  • 16
  • 36
0

now in kotlin you could just use

file1.copyTo(file2)

where file1 is an object of the original file and file2 is an object of the new file you want to copy to

0

Simple and easy way...!

import android.os.FileUtils;

try (InputStream in = new FileInputStream(sourceFile); 
     OutputStream out = new FileOutputStream(destinationFile) ){
                
     FileUtils.copy(in, out); 

}catch(Exception e){
     Log.d("ReactNative","Error copying file: "+e.getMessage());
}
CrackerKSR
  • 1,380
  • 1
  • 11
  • 29