2013-12-06 2 views
8

Мне нужно сбросить 6 миллионов файлов, которые содержат около 100-200 символов, и это очень медленно. Фактическая медленная часть - это запись файла, если я прокомментирую эту часть (вызов метода WriteSoveraFile), все это работает через 5-10 минут. Как бы то ни было, я запустил его на ночь (16 часов) и получил 2 миллиона записей.Быстрый способ записи миллионов небольших текстовых файлов в Java?

  1. есть ли какой-либо более быстрый способ?

  2. Могу ли я лучше создать массив массивов, а затем сбросить его все сразу? (Моя система имеет только 4 ГБ, не умрет от 6 ГБ потребленных этим данным?)

Вот процедура:

public static void WriteSoveraFile(String fileName, String path, String contents) throws IOException { 

    BufferedWriter bw = null; 

    try { 
     String outputFolderPath = cloGetAsFile(GenCCD.o_OutER7Folder).getAbsolutePath() ; 
     File folder = new File(String.format("%1$s/Sovera/%2$s/", outputFolderPath, path)); 

     if (! folder.exists()) { 
      folder.mkdirs(); 

/*   if (this.rcmdWriter != null) 
       this.rcmdWriter.close(); 
*/   
     } 

     File file = new File(String.format("%1$s/%2$s", folder.getAbsolutePath(),fileName)); 

     // if file doesnt exists, then create it 
     if (!file.exists()) { 
      file.createNewFile(); 
      FileWriter fw = new FileWriter(file.getAbsoluteFile()); 
      bw = new BufferedWriter(fw); 
      bw.write(contents); 
      bw.close(); 
     } 
/*  else { 
      file.delete(); // want to delete the file?? or just overwrite it?? 
      file.createNewFile();*/ 

    } catch (IOException e) { 
     e.printStackTrace(); 
    } finally { 
     try { 
      if (bw != null) bw.close(); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 
    } 
} 
+4

Ну, если вам действительно нужно написать 6 миллионов отдельных файлов, это займет некоторое время, и это будет медленным, потому что жесткие диски медленны. Я не знаю, влияете ли вы на это, но в этом масштабе данных я бы подумал об использовании базы данных вместо файлов. – LionC

+0

Вы рассмотрели использование системы управления базами данных для хранения метаданных? – NPE

+0

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

ответ

3

Это почти наверняка проблема файловой системы ОС; писать много файлов просто медленно. Я рекомендую написать сравнительный тест в оболочке и на C, чтобы получить представление о том, сколько ОС вносит свой вклад. Кроме того, я бы предложил две основные настройки:

  • Убедитесь, что система работает на SSD. Латентность от поиска журналирования файловой системы будет основным источником накладных расходов.
  • Многопользовательский процесс написания. Сериализованная ОС не может выполнять оптимизации, такие как запись в режиме пакетной обработки, а FileWriter может блокировать операцию close().

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

+0

Я действительно пробовал его на флеш-накопителе, и операция записи упала с 100 файлов/сек до 6 файлов/сек (USB2). Согласитесь, нам может понадобиться более быстрая машина, я запускаю ее на корпоративном ноутбуке (с не SSD-диском). – Rob

+2

@ Rob Не основанный на USB-накопителе флэш-накопитель на базе USB, настоящий Samsung или Intel. Чтобы добавить один из них в большинство ноутбуков, вам понадобится eSATA. Чтобы получить сравнение, попробуйте записать его на RAM-диск. – chrylis

+0

Понял, спасибо. Я буду работать над этим. – Rob

4

Вы можете использовать nio пакет. Это быстрее, чем io. Посмотрите: http://tutorials.jenkov.com/java-nio/nio-vs-io.html

Преимущества от NIO:
1. Буфер-ориентированный
2. Неблокирующая IO

Поскольку неблокирующая, вы можете создать файл, запись данных на нее и он будет храниться в буфере. Затем ваше приложение может перейти к следующему файлу, записать данные в буфер и т. Д. И т. Д. Это означает, что вам не нужно ждать, пока данные будут фактически записаны, прежде чем продолжить.

Это позволит вам сэкономить много времени, учитывая миллионы файлов. Поэтому, даже если это сэкономит вам четверть секунды, умножьте его на миллион и выполните математику =)

+5

Применяется при записи большого количества данных в файл. Не применимо при записи данных во множество отдельных файлов; операции файловой системы будут блокироваться в самой ОС. – chrylis

+0

@chrylis Ничто не может быть сделано об этом Java. Любое решение? =) Кроме того, почему бы не использовать более быстрый ввод-вывод с помощью 'nio'? ОС уже медленна, и поверх нее используется пакет 'io'. –

-1

Не используйте BufferedWriter. Используйте метод write() класса FileWriter.

+3

Это должен быть комментарий, сэр, а не ответ =) –

2

Как уже упоминалось, ограничивающим фактором является доступ к хранилищу, а не ваш код или JVM. В коде есть несколько вещей, которые улучшают код, но изменения останутся незамеченными, поскольку основным узким местом является файл IO.

Есть несколько возможных способов ускорить процесс:

  • Записать на более быстрый диск (выше RPM жесткий диск или SSD - не диск USB, поскольку USB связь намного медленнее, чем SATA.)
  • Используйте несколько потоков для записи на рейдовый диск. Есть уровни RAID (не помню, какие), которые поддерживают одновременную запись.
  • Пересмотреть структуру файла таким образом, чтобы не было необходимости иметь 6 миллионов файлов. Если файлы находятся в одном месте, я не уверен, зачем вам так много маленьких файлов. Функциональность, вероятно, может быть достигнута путем создания 1 или 2 файла большего размера, который принимает все данные. Вам просто нужно изменить формат и компонент чтения. Один файл будет 200 символов * 2 * 6 миллионов = ~ 2,4 ГБ (200 символов при 2 байтах/часовое время 6 миллионов файлов).
Смежные вопросы