Это просто вызывает список файлов Java

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

После того как я сгенерировал индекс, есть ли быстрый способ узнать, какие файлы были добавлены или удалены на диске с момента последнего запуска?

РЕДАКТИРОВАТЬЯ не хочу отслеживать события файловой системы. Я думаю, что риск слишком высок, чтобы выйти из синхронизации, я бы предпочел иметь что-то вроде быстрого повторного сканирования, которое быстро находит, где файлы были добавлены / удалены. Может быть, с каталогом даты последнего изменения или что-то?

Маленький эталон

Я только что сделал небольшой тест. Бег

dir /b /s M:\tests\  >c:\out.txt

Занимает 0,9 секунды и дает мне всю необходимую информацию. Когда я использую реализацию Java (так же, как это), это займет около 4,5 секунд. Любые идеи, как улучшить хотя бы этот метод грубой силы?

Похожие сообщения:Как посмотреть, изменился ли подфайл каталога

 Coderer04 февр. 2009 г., 16:53
Кроме того, почему вы думаете, что мониторинг событий файловой системы может привести к потере синхронизации? Я не знаю, в Java, но в C # /. NET вы можете создавать прослушиватели событий, которые запускаются каждый раз, когда файл или каталог по указанному пути добавляются или удаляются, и это работает в 100% случаев ...
 Zach Scrivena30 янв. 2009 г., 03:03
Можем ли мы предположить, что нас интересуют только добавленные и удаленные файлы, то есть мы индексируем только имена файлов, а все остальное (например, размер, время последнего изменения, криптографический хэш) не имеет значения?
 martinus04 февр. 2009 г., 17:16
@ Кодер, потому что тогда требуется, чтобы приложение работало все время. Возможно, лучше всего быстро найти изменения каталога, как в ответе Аарона Дигуллы, а затем использовать прослушиватель событий во время работы приложения.
 Coderer04 февр. 2009 г., 16:52
Можем ли мы предположить, что это исключительно для платформы Windows? Можете ли вы воспользоваться предоставленной Microsoft службой Index (вместо того, чтобы использовать свою собственную)?

Ответы на вопрос(10)

рсиями ориентировано на решение этой проблемы, и git имеет хорошую репутацию в отношении скорости; он специально разработан для быстрой работы с локальными файлами. 'git diff --name-status' даст вам то, что вы хотите, я думаю.

 martinus05 февр. 2009 г., 12:55
Я хочу проиндексировать большие файловые системы с миллионами файлов

в Java нет стандартного способа прослушивания событий файловой системы. Этотмай приходить в java7.

На данный момент вам нужно будет google "java filesystem events" и выбрать пользовательскую реализацию, соответствующую вашей платформе.

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

 Aaron Digulla04 февр. 2009 г., 09:10
Вам придется проверять каждый каталог, так как окна не распространяются, но это все равно будет быстрее, поскольку вы знаете все пути из вашего последнего запуска индекса. Я делал это раньше, и это работает. Ускорение огромно!
 martinus27 янв. 2009 г., 16:05
не работает, windows не распространяет изменения

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

 Guillaume29 янв. 2009 г., 17:11
вычисление хеша MD5 потребует чтения всего файла. Не очень хорошо, если вы ищете производительность ...
 Rad29 янв. 2009 г., 17:19
На самом деле. Вот почему я предложил сравнительный анализ, чтобы проверить, является ли производительность приемлемой. Любые идеи, как лечить файл, который восстанавливается из резервной копии?
 ScArcher226 янв. 2009 г., 16:37
Я написал что-то похожее, чтобы найти дубликаты файлов на моем жестком диске. MD5 был довольно медленным. Я пробовал многопоточность программы, но она просто заставила мой компьютер сканировать.

Вы могли бы просто использовать

dir /b /s /on M:\tests\  

/ на сортирует по имени

если вы передадите это в out.txt

Затем выполните diff, чтобы последний раз запускать этот файл на Java или в командном файле. Примерно так в Дос. Вам нужно получить инструмент сравнения, либо diff в cygwin, либо отличныйhttp://gnuwin32.sourceforge.net/packages/diffutils.htm

dir /b /s /on m:\tests >new.txt
diff new.txt archive.txt >diffoutput.txt
del archive.txt
ren new.txt archive.txt

Очевидно, что вы также можете использовать класс java diff, но я думаю, что нужно принять тот факт, что команда оболочки почти всегда превосходит Java при операции со списком файлов.

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

Вы упоминаете, что ваша реализация Java (похожа наэто) очень медленный по сравнению сdir /s«Я думаю, что для этого есть две причины:

File.listFiles() медленный по своей сути. Смотрите этот предыдущий вопросЕсть ли обходной путь для низкой производительности Java при обходе огромных каталогов?"и это Java RFE"File.list (FilenameFilter) не эффективен для огромных каталогов«Для получения дополнительной информации. Этот недостаток, по-видимому, устраненыNIO.2, скоро будет.

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

Как насчет чего-тонравится:

private static String execute( String command ) throws IOException  { 
    Process p = Runtime.getRuntime().exec( "cmd /c " + command );
    InputStream i = p.getInputStream();
    StringBuilder sb = new StringBuilder();
    for(  int c = 0 ; ( c =  i.read() ) > -1  ; ) {
        sb.append( ( char ) c );
    }
    i.close();
    return sb.toString();
}

( Существуетмного возможности для улучшения, так как эта версия читает по одному символу за раз: вы можете выбрать лучшую версиюотсюда читать поток быстрее)

И вы используете в качестве аргумента:

"dir /b /s M:\tests\"

Если это будет использоваться в работающем приложении (а точнее в качестве автономного приложения), вы можете сбрасывать со счетов время «разогрева» JVM, которое составляет около 1–2 секунд в зависимости от вашего оборудования.

Вы можете попытаться увидеть, как это повлияет.

 OscarRyz04 февр. 2009 г., 19:11
@martinus: ммхх что-то в строках: String s = getFileList (); Arrays.sort (s.split (lineSep)); Может быть?
 martinus04 февр. 2009 г., 09:50
Я пробовал это таким образом, но тупой порядок dir затрудняет использование при сканировании иерархий.

listFiles () метод. Возможно, стоит попробовать.

 martinus29 янв. 2009 г., 19:23
Это просто вызывает список файлов Java

что эту задачу очень трудно выполнить эффективно. Я уверен, что MS внедрила бы инструмент, похожий на Windows, если бы это было легко, особенно в наше время, так как HD растет и растет.

Решение Вопроса

Если индекс пуст, добавьте корневой каталог в индекс с отметкой времени == dir.lastModified () - 1.Найти все каталоги в индексеСравните метку времени каталога в индексе с меткой из файловой системы. Это быстрая операция, поскольку у вас есть полный путь (не требуется сканирование всех файлов / каталогов в дереве).Если метка времени изменилась, у вас есть изменения в этом каталоге. Пересканируйте его и обновите индекс.Если на этом этапе вы обнаружите отсутствующие каталоги, удалите поддерево из индексаЕсли вы столкнулись с существующим каталогом, игнорируйте его (будет проверено на шаге 2)Если вы столкнулись с новым каталогом, добавьте его с меткой времени == dir.lastModified () - 1. Убедитесь, что это рассматривается на шаге 2.

Это позволит вам эффективно заметить новые и удаленные файлы. Так как на шаге 2 вы сканируете только известные пути, это будет очень эффективно. Файловые системы плохо перечисляют все записи в каталоге, но они быстры, когда вы знаете точное имя.

Недостаток: вы не заметите измененные файлы. Так что, если вы редактируете файл, это будетне отразить в смене каталога. Если вам также нужна эта информация, вам придется повторить приведенный выше алгоритм для файловых узлов в вашем индексе. На этот раз вы можете игнорировать новые / удаленные файлы, потому что они уже были обновлены во время запуска по каталогам.

[ПРАВКА] Зак упомянул, что отметок времени недостаточно. Мой ответ: просто нет другого способа сделать это. Понятие «размер» совершенно не определено для каталогов и изменений от реализации к реализации. Нет API, в котором вы можете зарегистрироваться «Я хочу получать уведомления о любых изменениях, вносимых в файловую систему». Есть API-интерфейсы, которые работают, пока ваше приложение живо, но если оно останавливает или пропускает событие, значит, вы не синхронизированы.

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

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

Единственный другой способ добиться того, чего хочет Зак, - это создать новую файловую систему, которая постоянно хранит эту информацию где-нибудь, продавать ее Microsoft и ждать несколько лет (вероятно, 10 или более), пока все не используют ее.

 martinus04 февр. 2009 г., 16:53
Пока что это лучший ответ. Знаете ли вы, является ли это особенность файловой системы, или это сохранить, чтобы использовать его где-нибудь?
 Zach Scrivena04 февр. 2009 г., 17:48
@ Аарон: Предполагает ли этот подход, что последняя измененная временная метка каталога изменяется всякий раз, когда файл добавляется / удаляется? Что происходит, если временные метки каталога изменяются извне, например, на ощупь? (Продолжение)
 Zach Scrivena04 февр. 2009 г., 17:49
(продолжение) Кроме того, использование временных меток может быть недостаточно хорошим в некоторых файловых системах, например FAT имеет точность только 2 секунды, поэтому быстро происходящие изменения могут остаться незамеченными.
 Aaron Digulla05 февр. 2009 г., 09:33
@ Зач: Тогда ты читаешь DIR даром. Но урона мало, так как вы будете читать только этот единственный каталог.
 Aaron Digulla04 февр. 2009 г., 17:20
Он работает с файловой системой Unix и с Windows. Я не тестировал с HFS, но я был бы удивлен, если были какие-либо проблемы.

Ваш ответ на вопрос