File.lastModified () мучительно медленно! - PullRequest
4 голосов
/ 29 ноября 2010

Я делаю рекурсивную копию файлов, например xcopy /D Я хочу копировать только файлы назначения новых файлов (я не могу использовать xcopy напрямую, поскольку изменить некоторые файлы в процессе копирования).

В Java я использую lastModified(), чтобы проверить, является ли файл назначения старше, чем исходный файл, и он очень медленный.

  • Могу ли я ускорить процесс (возможно, используя JNI ??)?
  • Существуют ли другие сценарии копирования, которые могут лучше выполнять работу (копировать новые файлы + регулярные выражения изменять некоторые текстовые файлы)?

Копировать файлы в любом случае нельзя, так как это займет больше времени, чем проверка даты последнего изменения (копирование по сети).

Ответы [ 4 ]

3 голосов
/ 29 ноября 2010

Вы должны определить, почему это так медленно.

Когда вы запускаете progrma, какова загрузка ЦП вашего процесса.Если это более 50% пользователей, то вы должны иметь возможность оптимизировать свою программу, если ее менее 20% не так много, что вы можете сделать.

Обычно этот метод медленный, потому что файл, который выисследование находится на диске, а не в памяти.Если это так, вам нужно ускорить доступ к диску или получить более быстрый диск.например, SSD может делать это в 10-100 раз быстрее.

Может помочь массовый запрос.Вы можете сделать это, используя несколько потоков для проверки даты lastModified.например, иметь пул потоков фиксированного размера и добавить задачу для каждого файла.Размер пула потоков определяет количество одновременно опрашиваемых файлов.

Это позволяет ОС переупорядочивать запросы в соответствии с разметкой на диске.Примечание. Теоретически это нормально, но вам нужно проверить, ускоряет ли это работу на вашей ОС / оборудовании, так же как и вероятность замедления.;)

1 голос
/ 17 апреля 2015

Итак, я столкнулся с этим на сетевых дисках. Болезненные. У меня был каталог с 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;
1 голос
/ 01 декабря 2010

Я полагаю, вы делаете это по сети, иначе в копии не было бы особого смысла. Операции с сетевыми каталогами идут медленно, не повезло. Вы всегда можете просто скопировать файл ниже определенного порогового размера, в зависимости от того, что всего процесса занимает меньше времени.

Я не согласен с Крисом: нет ничего поразительно неэффективного в том, как Java это делает, и в любом случае это действительно должно быть так, потому что вам нужно самое последнее значение.

1 голос
/ 29 ноября 2010

К сожалению, Java обрабатывает поиск lastModified медленно (в основном он запрашивает базовую файловую систему для каждого файла при запросе информации, нет массовой загрузки этих данных в listFiles или аналогичные).Вы можете потенциально вызвать более эффективную нативную программу для массового выполнения этой задачи, но любое такое решение будет тесно связано с платформой, на которой вы развертываете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...