• 请慎用java的File#renameTo(File)方法(转)


    以前我一直以为File#renameTo(File)方法与OS下面的 move/mv 命令是相同的,可以达到改名、移动文件的目的。不过后来经常发现问题: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));

    结果: 

    source file is exist? true, source file => c:	est.txt
    e:	est.txt is exist? false
    rename to e:	est.txt => false
    source file is exist? true, source file => c:	est.txt
    d:	est.txt is exist? false
    rename to d:	est.txt => true

    注意看结果,从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是文件和目录路径名的抽象表示形式,所以有可能是目录,千万小心。

    文件系统不一样好像是说 windows和Linux的文件默认为NTFS的 而Linux是ext32的

    在大压力情况下在windows renameTo有一定概率失败的情况。
    在linux操作系统上在不同盘符之间renameTo也会失败。典型的应用场景就是从本地硬盘renameTo到mount的硬盘上或文件系统上。 

    copy文件尽量使用FileUtilsc.opyFileToDirectory(File,File) 

    还有个问题是在使用webwork的fileUpload拦截器的时候尽量不要使用execAndWait拦截器,两个拦截器会开启两个线程,很可能会删掉还没有处理的临时上传文件文件而导致文件找不到。

    http://xiaoych.iteye.com/blog/149328

  • 相关阅读:
    实战:第十二章:txt文件转xml文件
    实战:第十三章:HTTP Status 500 – Internal Server Error(解决SpringBoot架构的Web项目部署到linux系统上访问出错)
    理论:第一章:HashMap底层实现原理,红黑树,B+树,B树的结构原理,volatile关键字,CAS(比较与交换)实现原理
    【Java面试】第一章:P5级面试
    JavaSE:第十三章:一分钟了解反射
    我的收藏:第四章:八十种在线工具
    Error: Node Sass version 7.0.1 is incompatible with ^4.0.0.
    render: h => h(App)解析
    Could not find artifact org.openjfx:javafx.base:pom:11.0.0SNAPSHOT in aliyunmaven
    测试Mockjs用法的关键代码
  • 原文地址:https://www.cnblogs.com/softidea/p/4273112.html
Copyright © 2020-2023  润新知