注册
 找回密码
 注册
江西广告网
查看: 447|回复: 0
打印 上一主题 下一主题

Java的File#renameTo(File)方法的陷井

[复制链接]

该用户从未签到

1
跳转到指定楼层
发表于 2009-2-28 11:12:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有帐号?注册

x
以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名、移动文件的目的。不过后来经常发现问题,真的很bt,File#renameTo(File)方法会返回失败(false),文件没有移动,又查不出原因,再后来干脆弃用该方法,自己实现一个copy方法,问题倒是再也没有出现过。 昨天老板同学又遇到这个问题,File#renameTo(File)方法在windows下面工作的好好的,在linux下偶尔又失灵了。回到家我扫了一遍JDK中File#renameTo(File)方法的源代码,发现它调用的是一个本地的方法(native method),无法再跟踪下去。网上有人说该方法在window下是正常的,在linux下面是不正常的。这个很难说通,SUN不可能搞出这种平台不一致的代码出来啊。 后面在SUN的官方论坛上看到有人提到这个问题“works on windows, don't work on linux”,后面有人回复说是“file systems”不一样。究竟怎么不一样呢?还是没有想出来…… 后面在一个论坛里面发现了某人关于这个问题的阐述:In the Unix'esque O/S's you cannot renameTo() across file systems. This behavior is different than the Unix "mv" command. When crossing file systems mv does a copy and delete which is what you'll have to do if this is the case. The same thing would happen on Windows if you tried to renameTo a different drive, i.e. C: -> D:终于明白咯。 做个实验: File sourceFile = new File("c:/test.txt"); File targetFile1 = new File("e:/test.txt"); File targetFile2 = new File("d:/test.txt"); System.out.println("source file is exist? " sourceFile.exists() ", source file => " sourceFile); System.out.println(targetFile1 " is exist? " targetFile1.exists()); System.out.println("rename to " targetFile1 " => " sourceFile.renameTo(targetFile1)); System.out.println("source file is exist? " sourceFile.exists() ", source file => " sourceFile); System.out.println(targetFile2 " is exist? " targetFile2.exists()); System.out.println("rename to " targetFile2 " => " sourceFile.renameTo(targetFile2)); 注意看结果,从C盘到E盘失败了,从C盘到D盘成功了。因为我的电脑C、D两个盘是NTFS格式的,而E盘是FAT32格式的。所以从C到E就是上面文章所说的"file systems"不一样。从C到D由于同是NTFS分区,所以不存在这个问题,当然就成功了。 果然是不能把File#renameTo(File)当作move方法使用。 可以考虑使用apache组织的commons-io包里面的FileUtils#copyFile(File,File)和FileUtils#copyFileToDirectory(File,File)方法实现copy的效果。至于删除嘛,我想如果要求不是那么精确,可以调用File#deleteOnExit()方法,在虚拟机终止的时候,删除掉这个目录或文件。 BTW:File是文件和目录路径名的抽象表示形式,所以有可能是目录,千万小心。 下面我写的一个实现方法 /** * 使用FileChannel拷贝文件 * * @param srcFile * @param destFile * @throws IOException */ public static void copyUseChannel(File srcFile, File destFile) throws IOException { if ((!srcFile.exists()) || (srcFile.isDirectory())) { return; } if (!destFile.exists()) { createFile(destFile.getAbsolutePath()); } FileChannel out = null; FileChannel in = null; try { out = new FileOutputStream(destFile).getChannel(); in = new FileInputStream(srcFile).getChannel(); ByteBuffer buffer = ByteBuffer.allocate(102400); int position = 0; int length = 0; while (true) { length = in.read(buffer, position); if (length <= 0) { break; } // System.out.println("after read:" buffer); buffer.flip(); // System.out.println("after flip:" buffer); out.write(buffer, position); position = length; buffer.clear(); // System.out.println("after clear:" buffer); } } finally { if (out != null) { out.close(); } if (in != null) { in.close(); } } }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表