2010-11-29 4 views
4

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

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

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

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

ответ

3

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

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

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

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

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

+0

Я использовал метод пула потоков. Намного быстрее! – dacwe 2010-12-07 09:09:22

0

Проверено ли вы на проверку this?

+0

Я просто обновляю ссылку. – ozhan 2010-11-29 16:07:38

+0

Это медленный процесс lastModified(), который видит, что `FileUtils` делает это для меня (копирование файлов с той же последней измененной датой не является вариантом - это еще медленнее). – dacwe 2010-11-29 16:13:34

1

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

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

1

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

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

0

Так что я столкнулся с этим на сетевых дисках. Болезненные. У меня был каталог с 17000 + файлами. На локальном диске потребовалось менее 2 секунд, чтобы проверить последнюю измененную дату. На сетевом диске это заняло 58 секунд !!! Конечно, мое приложение - интерактивное приложение, поэтому у меня были некоторые жалобы.

После некоторого исследования я решил, что можно будет реализовать некоторый код JNI, чтобы сделать файл findfirstfile/findnextfile/findclose Windows Kernel32, чтобы значительно улучшить процесс, но потом у меня была 32-разрядная и 64-разрядная версия и т. Д. а затем потерять возможности кросс-платформы.

Хотя немного неприятный взлом здесь - это то, что я сделал. Мое приложение работает в основном в Windows, но я не хотел его ограничивать, поэтому я сделал следующее. Проверьте, работает ли я на окнах. Если да, то посмотрите, использую ли я локальный жесткий диск. Если нет, мы собираемся сделать хакерский метод.

Я хранил все нечувствительные к регистру. Вероятно, это не отличная идея для других ОС, которые могут иметь каталог с обоими «ABC» и «abc». Если вам нужно это сделать, вы можете решить, создав новый файл («ABC») и новый файл («abc»), а затем используя метод equals для их сравнения. На нечувствительных к регистру файловых системах, таких как окна, он вернет 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;