读取多个文件时出现内存分配错误

时间:2018-05-16 22:43:38

标签: fortran

我尝试打开6个不同的文件(至少),然后读取每个文件中的行数,每个文件大约应该有20,000行。我已经在这个论坛上阅读了一些关于如何做到这一点的帖子,因为我是一个新手,并且我已经尝试为我的目的实施它。

我可以单独执行此操作而没有任何问题,但是当我尝试读入所有文件时,我收到一条错误消息。我得到了" 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进行编译。

更新

我创建了6个测试文件data_0000000.txt,data_0000200.txt,...,data_0001000.txt,每个文件少于10行,每行少于100个字符。不幸的是,我得到了同样的错误。

3 个答案:

答案 0 :(得分:1)

强制性免责声明:如果您只想知道文件中的行数,请使用wc -l <filename>。如果你不需要,不要重新发明轮子。

我写这不一定是因为我认为你不知道,但因为其他人可能会出现,并认为他们需要编写自己的程序来获取文件行数。

至于你的问题:我不知道为什么你会收到malloc错误。也许告诉我们你正在使用哪个编译器和系统(包括版本)?也就是说,在阅读代码时我注意到了三件事:

  1. 您创建了一个变量FILENAME,但之后就不再使用它了。你引用它:FILE='FILENAME'这意味着open命令会查找一个字面上称为FILENAME的文件,而不是名称存储在变量FILENAME中的文件。删除引号:

    OPEN(1, FILENAME=FILENAME, FORM='FORMATTED')
    
  2. 您使用单位编号1 - 这很危险。不同版本的Fortran使用特定的单位编号进行特定用途。使用更大(至少10或更多)的句柄,或者甚至更好地使用open语句中的newunit描述符:

    INTEGER :: u
    
    OPEN(NEWUNIT=u, FILE=FILENAME, ACTION='READ', FORM='FORMATTED')
    
    READ(u, *, IOSTAT=IO)
    
    CLOSE(u)
    
  3. 您没有在文件之间将NLINES变量重置为0。程序将打印累积总和,而不是直接打印每个文件的行数。

答案 1 :(得分:0)

添加到@ chw21的响应,如果你的唯一目的是计算文件中的记录(行)数,这里有一个模块化的解决方案和一个测试程序(计数在子程序{{1}内完成) }):

getNumRecordInFile()

现在,如果您将此代码放在名为“main.f95”的文件中并在Fortran 2008标准下进行编译,那么它应该输出“main.f95”文件中的行数,这应该类似于以下内容:

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

对于测试,您只需复制粘贴在线Fortran编译器中的整个代码:https://www.tutorialspoint.com/compile_fortran_online.php 但请记住,在执行代码之前,请转到$gfortran -std=f2008 *.f95 -o main $main Total number of records in file='main.f95': 98 ,将编译选项-std=f95更改为-std=f2008

答案 2 :(得分:-1)

尝试这个更改(声明和读取行),没有指定行内容的变量,这里插入虚拟...

character(len=1000) :: dummy
...
READ(u, '(a)' , IOSTAT=IO) dummy
....