5

I'm reading the documentation of renameTo(File) in the File.class of the Android SDK doc.

We've been using this method for a while in production, still I have been wondering what are the possible things that can go wrong. The documentation says

Renames this file to newPath. This operation is supported for both files and directories.

Many failures are possible. Some of the more likely failures include:

  • Write permission is required on the directories containing both the source and destination paths.

  • Search permission is required for all parents of both paths.

  • Both paths be on the same mount point. On Android, applications are most likely to hit this restriction when attempting to copy between internal storage and an SD card. Note that this method does not throw IOException on failure. Callers must check the return value.

What are other possible reasons why renameTo() might fail (referring to more likely failures)? Is there a guaranteed state after calling renameTo? When renameTo() fails, can I rely on having still my original file? Any other conditions I want to check to uber sure that it works beside the described ones from the docs?

4

3 回答 3

3

列出的三个是更有可能失败的。不太可能(但可能!)失败包括

  • 用户错误(例如源是文件,目标是现有目录,反之亦然)
  • 设备上没有剩余空间
  • 文件系统以只读方式挂载
  • 损坏的文件系统
  • 旋转磁盘上的坏扇区
  • ...

由于 Android 是基于 Linux 的,你可能可以依赖这些:

  • 如果重命名失败,则两个文件都保持原样
  • 如果目标文件存在并且重命名成功,则任何进程都不会发现目标文件丢失(替换是原子的)
于 2013-08-21T23:45:56.327 回答
2

在 Android File.renameTo 中调用 Linux rename()(通过 libcore)。您可以检查POSIX 标准以获取可能的故障列表,它在 Linux 上可能略有不同,但应该给您一个大致的概念。

另请注意此声明:

如果 rename() 函数由于 [EIO] 以外的任何原因而失败,则任何以 new 命名的文件均不受影响。

于 2013-08-21T23:44:51.240 回答
1

For the reason that I don't know, it's not possible to use file.rename() to move files between to different mounted directory in Android (like sdcard0 and sdcard1), here is my solution and it work for me:

if(canRename(f1, f2)) {
    if(!f1.renameTo(f2)) {
        Log.e(TAG, "Error to move new app: " + f1 + " > " + f2);
    }
} else {
    try {
        copy(f1, f2);
        f1.delete();
    } catch (Exception ex) {
        Log.e(TAG, "Error to move new app: " + f1 + " > " + f2);
    }
}

private void copy(final File f1, final File f2) throws IOException {
    f2.createNewFile();

    final RandomAccessFile file1 = new RandomAccessFile(f1, "r");
    final RandomAccessFile file2 = new RandomAccessFile(f2, "rw");

    file2.getChannel().write(file1.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, f1.length()));

    file1.close();
    file2.close();
}

private boolean canRename(final File f1, final File f2) {
    final String p1 = f1.getAbsolutePath().replaceAll("^(/mnt/|/)", "");
    final String p2 = f2.getAbsolutePath().replaceAll("^(/mnt/|/)", "");

    return p1.replaceAll("\\/\\w+", "").equals(p2.replaceAll("\\/\\w+", ""));
}
于 2013-11-14T09:49:13.270 回答