bt下载与小说520

bt下载与小说520

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  16 随笔 :: 0 文章 :: 6 评论 :: 0 Trackbacks

以前我一直以为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();
       }
      }
     }

    posted on 2008-10-27 10:15 bt下载 阅读(1654) 评论(2)  编辑  收藏

    评论

    # re: java的File#renameTo(File)方法的陷井 2008-10-27 11:24 temper
    收藏。最近正好要用到这个方法,回去先验证一下  回复  更多评论
      

    # re: java的File#renameTo(File)方法的陷井 2008-10-27 12:37 moron128
    也遇到过这个问题
    还有目标路径下如有同名文件时好像无法覆盖
    需要事先判断  回复  更多评论
      


    只有注册用户登录后才能发表评论。


    网站导航: