0

My problem is not How to make a copy of a File in Android, My problem is why it fails to make a copy.

After my app downloads a file am trying to copy it to another folder (The end user can save the file in several folder, that why i download once and copy to the rest). I do have the origin file path like:

/storage/emulated/0/MyAppFolder/FolderCreatedByUser1/theFile.pdf

And am trying to copy it to

/storage/emulated/0/MyAppFolder/FolderCreatedByUser2/

With this code (Code improved by Robert Nekic):

public static boolean copyFile(File src, File[] dst) {
boolean result = true;
if (src.exists()) {
    String srcName = src.getName();
    for (File file : dst) {
        String to = file.getPath();
        try {
            File destination = new File(to, srcName);
            if (destination.createNewFile()) {
                FileChannel srcChnl = new FileInputStream(src).getChannel();
                FileChannel dstChnl = new FileOutputStream(destination).getChannel();
                dstChnl.transferFrom(srcChnl, 0, srcChnl.size());
                srcChnl.close();
                dstChnl.close();
            } else {
                result = false;
                System.out.println("Unable to create destination " + destination.getPath());
            }
        } catch (Exception e) {
            result = false;
            System.out.println(e.getMessage());
            break;
        }
    }
} else {
    result = false;
    System.out.println("File " + src.getPath() + " doesn't exist.");
}
return result;
}

The file exist, but am keep getting errors when copying it to the destiny file like:

/storage/emulated/0/MyAppFolder/FolderCreatedByUser2/theFile.pdf: open failed: ENOENT (No such file or directory)

It fails in both streams, when trying to open the src file and/or destination file:

FileChannel srcChnl = new FileInputStream(src).getChannel();
FileChannel dstChnl = new FileOutputStream(destination).getChannel();

Permission to write are granted. The destination folders are created previously to the download of the file, the user can't select a destination if the directory isn't created.

Imacisco
  • 77
  • 1
  • 6
  • Possible duplicate of [How to make a copy of a file in android?](https://stackoverflow.com/questions/9292954/how-to-make-a-copy-of-a-file-in-android) – FlyingNades Apr 10 '18 at 19:54
  • @FlyingNades I already try it that. Same result. – Imacisco Apr 10 '18 at 19:59
  • @RobertNekic After destination = new File(to, srcName), I added "if (destination.createdNewFile())", and put the creation of the streams inside. Now am getting: open failed: ENOENT (No such file or directory) – Imacisco Apr 10 '18 at 20:25
  • Apologies, I deleted my comment and added it as an answer. Have you debugged the code to see exactly which line is throwing the error? – Robert Nekic Apr 10 '18 at 20:32
  • @RobertNekic both fileChannel fail to open FileChannel srcChnl = new FileInputStream(source).getChannel() FileChannel dstChnl = new FileOutputStream(destination).getChannel() open failed: ENOENT (No such file or directory) – Imacisco Apr 10 '18 at 21:07
  • See my updated answer. Perhaps the path substring stuff is resulting in a path that really does not exist. You don't really need all of that anyway. – Robert Nekic Apr 10 '18 at 21:17

1 Answers1

0

destination = new File(to, srcName); creates a new File instance but does not create the underlying file. You can verify by checking destination.exists(). I believe all you need is:

destination = new File(to, srcName);
destination.createNewFile();

Also, your src path string manipulation and stuff in the first half of your code seems unnecessary and might be introducing an error that could be resolved with something more concise:

public static boolean copyFile(File src, File[] dst) {
    boolean result = true;
    if (src.exists()) {
        String srcName = src.getName();
        for (File file : dst) {
            String to = file.getPath();
            try {
                File destination = new File(to, srcName);
                if (destination.createNewFile()) {
                    FileChannel srcChnl = new FileInputStream(src).getChannel();
                    FileChannel dstChnl = new FileOutputStream(destination).getChannel();
                    dstChnl.transferFrom(srcChnl, 0, srcChnl.size());
                    srcChnl.close();
                    dstChnl.close();
                } else {
                    result = false;
                    System.out.println("Unable to create destination " + destination.getPath());
                }
            } catch (Exception e) {
                result = false;
                System.out.println(e.getMessage());
                break;
            }
        }
    } else {
        result = false;
        System.out.println("File " + src.getPath() + " doesn't exist.");
    }
    return result;
}
Robert Nekic
  • 3,087
  • 3
  • 24
  • 36
  • Keep in mind that createNewFile() will return false if the file already exists, so you probably want to check that first. I don't know what you want to do in that case. Use a different destination file name and try again, I suppose. – Robert Nekic Apr 10 '18 at 21:30
  • Thanks for the clean up, that's a lot better. Just like my very cluttered code, it fail in both Streams. – Imacisco Apr 10 '18 at 21:36
  • I don't know what directories you are dealing with. Are you sure you have permission to read and write the source and destination? – Robert Nekic Apr 10 '18 at 22:06
  • Permissions to read and write are granted, the permission is requested at the start of the app, one time (If the user agrees). Folders can be created, renamed, and erased (by the user), this works, tested with debug, and signed .apk. The base directory where I create "MyAppFolder" is acquired with Environment.getExternalStorageDirectory(). – Imacisco Apr 10 '18 at 23:19
  • The folders that the user creates are inside "MyAppFolder", downloaded files end in a path like this "/storage/emulated/0/MyAppFolder/FolderCreatedByUser1/TheDownloadedFile.format". The downloads are made (.mp4, .pdf, .doc, etc) thru DownloadManager. The only thing that doesn't work is the copy of the file to the other folder(s) the user select(s) before downloading any file, once again, no folder can be selected as a destination if is not created previously – Imacisco Apr 10 '18 at 23:24
  • I tried this code in a small test app and it works for me. Hmm. – Robert Nekic Apr 11 '18 at 13:22
  • in device and/or emulation? I can't get it to work in any. At the moment I've decided to the let the user download the file in 1 destination, and if they decide, download it again to another directory, alerting them if the file already exist in the target folder. – Imacisco Apr 11 '18 at 21:28