2013-12-03 6 views
1

У меня есть 500 000 файлов, которые мне нужно прочитать в Fortran, и каждый файл имеет ~ 14 000 записей в нем (каждая запись содержит всего около 100 символов). Мне нужно обрабатывать каждую строку для каждого файла за раз. Например, мне нужно обработать строку 1 для всех 500 000 файлов, прежде чем переходить к строке 2 из файлов и т. Д.Чтение МНОГИХ файлов сразу в Fortran

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

do iline = 1,Nlines 
    do ifile = 1,Nfiles 
    ! open the file 
    ! read a line 
    ! close the file 
    enddo 
end 

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

Благодаря

+0

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

ответ

0

Вы можете попробовать использовать fseek и ftell в чем-то вроде следующего.

! initialize an array of 0's 
do iline = 1,Nlines 
    do ifile = 1,Nfiles 
    ! open the file 
    ! fseek(fd, array(ifile)) 
    ! read a line 
    ! array(ifile)=ftell(fd) 
    ! close the file 
    enddo 
end 

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

+1

Блестящий. Прежде чем я попробовал это, я пошел с «FSEEK» бедняка, просто выполнив поиск выделенной строки с помощью прочтений. Потребовалось ~ 8 минут, чтобы сделать это для 10 файлов, но теперь это время опустилось до ~ 4 секунд с 'FSEEK' – drjrm3

+2

Нестандартный Fortran. –

3

К сожалению, это не возможно, таким образом, в стандартном Fortran. Даже если вы укажете

position="ASIS" 

фактическое положение будет определено для уже не подключен блок и будет на самом деле начало файла на большинстве систем.

Это означает, что Вы должны использовать

read(*,*) 

достаточное количество раз, чтобы попасть на нужное место в файле.

Вы также можете использовать доступ stream. Файл будет вновь открыт в начале, но вы можете использовать

read(u,*,pos=n) number 

где n является позиция спасается от предыдущей открытой. Вы можете получить позицию из

inquire(unit=u, pos=n) 
n = n 

Вы бы открыть файл с acess="STREAM".

Также 500000 открытых файлов действительно слишком много. Существуют способы, как запросить системные ограничения и как их контролировать, но и ваш компилятор может иметь некоторые ограничения http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

Другое решение: Не удалось сохранить содержимое файлов в памяти? Сегодня пара гигабайтов в порядке, но вам этого может быть недостаточно.

+0

содержание всех данных превышает 130 ГБ. Я не могу хранить его в памяти или это было бы простым исправлением. Я действительно читаю его так, потому что все данные были в одном файле, и я должен был прочитать его таким образом, который потребовался бы ~ 4,5 года, чтобы закончить! Так что да, я могу изменить алгоритм, и текущая сборка - лучший вариант! – drjrm3

+0

Вы также можете попробовать «поток», но он может быть не быстрее. –

0

Если файлы имеют фиксированные, т. Е. Константы, длины записей, вы можете использовать прямой доступ. Затем вы можете «прямо» прочитать определенную запись. Однако большой «если».

0

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

псевдокод:

  loop until done: 
      loop over all files: 
       open 
       fseek !as in damiens answer 
       read N lines into array ! N=100 eg. 
       save ftell value for file 
       close 
      end file loop 
      loop over N output files: 
       open 
       write array data 
       close 
Смежные вопросы