代码之家  ›  专栏  ›  技术社区  ›  dacwe

File.lastModified()速度太慢了!

  •  4
  • dacwe  · 技术社区  · 14 年前

    我正在做一个文件的递归拷贝 xcopy /D 我只想复制较新的文件目标文件(I 不能 使用 xcopy 因为我需要在复制过程中更改一些文件)。

    在java中我使用 lastModified() 检查目标文件是否比源文件旧并且速度非常慢。

    • 我可以加速这个过程吗(也许使用JNI??)?
    • 有没有其他的复制脚本可以更好地完成这项工作(复制新文件+regexp更改一些文本文件)?

    无论如何复制文件都不是一个选项,因为这将花费比检查上次修改日期(通过网络复制)更多的时间。

    4 回复  |  直到 14 年前
        1
  •  3
  •   Peter Lawrey    14 年前

    你得弄清楚为什么这么慢。

    当您运行progrma时,进程的CPU利用率是多少。如果它超过50%的用户,那么你应该能够选择你的程序,如果它不到20%有没有那么多你可以做。

    通常这种方法比较慢,因为您正在检查的文件在磁盘上,而不是在内存中。如果是这种情况,您需要加快访问磁盘的速度,或获得更快的驱动器。例如,SSD的速度可以提高10-100倍。

    批量查询可能会有帮助。您可以使用多个线程来检查上次修改的日期。例如,有一个固定大小的线程池,并为每个文件添加一个任务。线程池的大小决定了一次轮询的文件数。

    这允许操作系统重新排序请求以适应磁盘上的布局。注意:这在理论上是很好的,但是您必须测试这是否会使您的操作系统/硬件上的速度更快,就像它可能会使速度更慢一样。;)

        2
  •  1
  •   Kris    14 年前

    不幸的是,Java处理查找lastmedited的方式很慢(基本上它在您请求信息时为每个文件查询底层文件系统,在listFiles或类似文件上不存在此数据的大容量加载)。

    您可以潜在地调用更高效的本机程序来批量执行此操作,但任何此类解决方案都将与您部署到的平台紧密相关。

        3
  •  1
  •   user207421    14 年前

    我想你是在网络上做这件事,否则复印件就没什么意义了。网络目录操作慢,运气不好。您总是可以将文件复制到某个大小阈值以下,无论是什么使总操作所需时间最少。

    我不同意Kris的观点:Java做这件事的方式没有什么惊人的低效,而且无论如何它确实必须这样做,因为你想要最新的价值。

        4
  •  1
  •   user3708686    9 年前

    所以我在网络驱动器上看到了这个。很痛苦。我有一个目录,上面有17000多个文件。在本地驱动器上,检查上次修改的日期所用的时间不到2秒。在一个联网的硬盘上花了58秒!!! 当然,我的应用程序是一个互动的应用程序,所以我有一些投诉。

    经过一些研究,我决定可以实现一些JNI代码来实现Windows Kernel32 findfirstfile/findnextfile/findclose,以显著改善进程,但后来我有了32位和64位版本等等。然后失去跨平台能力。

    尽管我在这里做了一点卑鄙的勾当。我的应用主要在windows上运行,但我不想限制它这样做,所以我做了以下操作。检查我是否在windows上操作。如果是的话,看看我是否在使用本地硬盘。如果不是,那我们就用黑客的方法。

    我把所有东西都不区分大小写。对于其他操作系统来说,可能不是一个好主意,因为它们可能有一个同时包含“ABC”和“ABC”文件的目录。如果您需要关心这个问题,那么您可以通过创建一个新文件(“ABC”)和一个新文件(“ABC”),然后使用equals方法进行比较来决定。在不区分大小写的文件系统(如windows)上,它将返回true,但在unix系统上,它将返回false。

    虽然这可能是一个有点黑客花的时间从58秒到1.6秒在网络驱动器上,所以我可以与黑客生活。

            boolean useJaveDefaultMethod = true;
    
        if(System.getProperty("os.name").startsWith("Windows"))
        {
            File f2 = f.getParentFile();
            while(true)
            {
                if(f2.getParentFile() == null)
                {
                    String s = FileSystemView.getFileSystemView().getSystemTypeDescription(f2);
                    if(FileSystemView.getFileSystemView().isDrive(f2) && "Local Disk".equalsIgnoreCase(s))
                    {
                        useJaveDefaultMethod = true;
                    }
                    else
                    {
                        useJaveDefaultMethod = false;
                    }
                    break;
                }
                f2 = f2.getParentFile();
            }
        }
        if(!useJaveDefaultMethod)
        {
            try
            {
                ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C", "dir " + f.getParent());
                pb.redirectErrorStream(true);
                Process process = pb.start();
                InputStreamReader isr = new InputStreamReader(process.getInputStream());
                BufferedReader br = new BufferedReader(isr);
    
                String line;
                DateFormat df = new SimpleDateFormat("dd-MMM-yy hh:mm a");
                while((line = br.readLine()) != null)
                {
                    try
                    {
                        Date filedate = df.parse(line);
                        String filename = line.substring(38);
                        dirCache.put(filename.toLowerCase(), filedate.getTime());
                    }
                    catch(Exception ex)
                    {
    
                    }
                }
                process.waitFor();
    
                Long filetime = dirCache.get(f.getName().toLowerCase());
                if(filetime != null)
                    return filetime;
    
            }
            catch(Exception Exception)
            {
            }
        }
    
        // this is SO SLOW on a networked drive!
        long lastModifiedDate = f.lastModified();
        dirCache.put(f.getName().toLowerCase(), lastModifiedDate);
    
        return lastModifiedDate;