Ошибка выделения памяти при чтении нескольких файлов - PullRequest
0 голосов
/ 17 мая 2018

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

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

malloc: *** mach_vm_map(size=63032829050880) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug

Что означает эта ошибка в отношении выделения памяти? Что я делаю неправильно? Как мне исправить это?

   PROGRAM X

   IMPLICIT NONE
   INTEGER :: J,IO,NFILES,NLINES
   CHARACTER (LEN=128) :: FILENAME

   NFILES = 6

   NLINES = 0

   DO J = 0,NFILES-1
      WRITE(FILENAME,'(A,I7.7,A)') 'data_',J*200,'.txt'
      OPEN(1,FILE='FILENAME',FORM='FORMATTED')
      DO
         READ(1,*,IOSTAT=IO)
         IF (IO/=0) EXIT
         NLINES = NLINES + 1
      END DO
      WRITE(*,*) NLINES
      CLOSE(1)
   END DO

   END PROGRAM X

Я использую gfortran для компиляции.


UPDATE

Я создал 6 тестовых файлов, data_0000000.txt, data_0000200.txt, ..., data_0001000.txt, каждый из которых содержит менее 10 строк, где в каждой строке содержится менее 100 символов. К сожалению, я получаю ту же ошибку.

Ответы [ 3 ]

0 голосов
/ 18 мая 2018

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

character(len=1000) :: dummy
...
READ(u, '(a)' , IOSTAT=IO) dummy
....
0 голосов
/ 20 мая 2018

Добавление к ответу @ chw21, если ваша единственная цель - подсчитать количество записей (строк) в файле, вот модульное решение и тестовая программа вместе с ним (подсчет выполняется внутри подпрограммы getNumRecordInFile()) :

module NumRecord_mod

    implicit none

    type :: Err_type
        logical                     :: occurred = .false.
        integer                     :: stat     = -huge(0)
        character(:), allocatable   :: msg
    end type Err_type

contains

    ! returns the number of lines in a file.
    subroutine getNumRecordInFile(filePath,numRecord,Err)
        implicit none
        character(len=*), intent(in)    :: filePath
        integer, intent(out)            :: numRecord
        type(Err_type), intent(out)     :: Err
        character(len=8)                :: record
        integer                         :: fileUnit
        logical                         :: fileExists, isOpen
        integer                         :: iostat

        character(*), parameter         :: PROCEDURE_NAME = "@getNumRecordInFile()"

        Err%occurred = .false.
        Err%msg = ""

        ! Check if file exists
        inquire( file=filePath, exist=fileExists, opened=isOpen, number=fileUnit, iostat=Err%stat )
        if (Err%stat/=0) then
            Err%occurred = .true.
            Err%msg = PROCEDURE_NAME // ": Error occurred while inquiring the status of file='" // filePath // "'."
            return
        end if
        if (.not.fileExists) then
            Err%occurred = .true.
            Err%msg = PROCEDURE_NAME // ": The input file='" // filePath // "' does not exist."
            return
        end if
        if (isOpen) close(unit=fileUnit,iostat=Err%stat)
        if (Err%stat>0) then
            Err%occurred = .true.
            Err%msg = PROCEDURE_NAME // ": Error occurred while attempting to close the open input file='" // filePath // "'."
            return
        end if

        open(newunit=fileUnit,file=filePath,status="old",iostat=Err%stat)
        if (Err%stat>0) then
            Err%occurred = .true.
            Err%msg = PROCEDURE_NAME // ": Error occurred while opening input file='" // filePath // "'."
            return
        end if

        numRecord = 0
        do
            read(fileUnit,'(A)',iostat=iostat) record
            if(iostat==0) then
                numRecord = numRecord + 1
                cycle
            elseif(is_iostat_end(iostat)) then
                exit
            else
                Err%occurred = .true.
                Err%stat = iostat
                Err%msg = PROCEDURE_NAME // ": Error occurred while reading input file='" // filePath // "'."
                return
            end if
        end do
        close(fileUnit,iostat=Err%stat)
        if (Err%stat>0) then
            Err%occurred = .true.
            Err%msg =   PROCEDURE_NAME // ": Error occurred while attempting to close the open input file='" // &
                        filePath // "' after counting the number of records in file."
            return
        end if

    end subroutine getNumRecordInFile


end module NumRecord_mod

program test_numRecord
    use NumRecord_mod
    implicit none
    type(Err_type)              :: Err
    integer                     :: numRecord
    character(:), allocatable   :: filePath
    filePath = "main.f95"
    call getNumRecordInFile(filePath=filePath,numRecord=numRecord,Err=Err)
    if (Err%occurred) then
        write(*,*) Err%msg
        write(*,*) Err%stat
        error stop
    else
        write(*,*) "Total number of records in file='" // filePath // "': ", numRecord
    end if
end program test_numRecord

Теперь, если вы поместите этот код в файл с именем "main.f95" и скомпилируете его в соответствии со стандартом Fortran 2008, он должен вывести количество строк в файле "main.f95", которое должно быть примерно таким: :

$gfortran -std=f2008 *.f95 -o main
$main
 Total number of records in file='main.f95':           98

Для тестирования вы можете просто скопировать и вставить весь код в онлайн-компилятор Fortran здесь: https://www.tutorialspoint.com/compile_fortran_online.php Но имейте в виду, что перед выполнением кода нужно изменить параметр компиляции -std=f95 на -std=f2008, перейдя к Project -> Compile Options.

0 голосов
/ 17 мая 2018

Обязательный отказ от ответственности: если вы просто хотите узнать количество строк в файле, используйте wc -l <filename>.Не изобретайте велосипед, если вам не нужно.

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

Что касается вашего вопроса: я не знаю, почему вы получаете ошибку malloc.Может быть, сообщите нам, какой компилятор и систему вы используете (включая версии)?Тем не менее, при чтении вашего кода я заметил три вещи:

  1. Вы создаете переменную FILENAME, но затем вы ее не используете.Вы цитируете это: FILE='FILENAME', что означает, что команда open ищет файл с буквальным названием FILENAME, а не файл с именем, хранящимся в переменной FILENAME.Убрать кавычки:

    OPEN(1, FILENAME=FILENAME, FORM='FORMATTED')
    
  2. Вы используете номер устройства 1 - это опасно.Различные версии Fortran используют конкретные номера единиц для конкретных целей.Используйте дескриптор гораздо большего размера (не менее 10 или более) или, что еще лучше, используйте дескриптор newunit в операторе open:

    INTEGER :: u
    
    OPEN(NEWUNIT=u, FILE=FILENAME, ACTION='READ', FORM='FORMATTED')
    
    READ(u, *, IOSTAT=IO)
    
    CLOSE(u)
    
  3. Вы не сбрасываетепеременная NLINES в 0 между файлами.Программа выведет суммарную сумму, а не количество строк для каждого файла напрямую.

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