Fortran从Python中读取单元

问题描述 投票:0回答:1

我正在寻找使用从基于文件的单元号读取的旧Fortran子程序。以下是一些固定格式FORTRAN77的示例:reader.f

      SUBROUTINE READER(IN,FVAL)
        IMPLICIT NONE
        INTEGER IN
        REAL FVAL
        PRINT *,'READER READING FROM',IN
        READ(IN,*) FVAL
        PRINT *,'READER DONE',FVAL
        RETURN
      END

在Linux上将其编译为共享库:

gfortran -fPIC -shared -o libdusty.so reader.f

这是Python中库对象的基本ctypes接口:

import os
from ctypes import CDLL, POINTER, c_int32, c_float, byref

c_int32_p = POINTER(c_int32)
c_float_p = POINTER(c_float)

so = CDLL('./libdusty.so')
reader = so.reader_

reader.argtypes = [c_int32_p, c_float_p]
reader.restype = None

如果没有open语句,Fortran会从文件#.fort中读取,其中#是文件单元号。从上面继续,我让Python编写一个临时文件来读取:

fval_in = 43.21
fnum_in = 12
fname_in = 'fort.' + str(fnum_in)
print('Writing ' + fname_in)
with open(fname_in, 'w') as fp:
    fp.write(str(fval_in) + '\n')

fval_out = c_float(0)
reader(byref(c_int32(fnum_in)), byref(fval_out))
print('Received fval: ' + str(fval_out.value))
os.unlink(fname_in)

从控制台(接收stdout),这里是完整的输出:

Writing fort.12
 READER READING FROM          12
 READER DONE   43.2099991    
Received fval: 43.2099990845

问题:是否需要基于磁盘的文件对象,或者是否可以使用非基于文件的流来读取?一个好的候选人是io.BytesIO,除了它不提供fileno()。还有一个相关的问题:在这个例子中,是否可以使用fort.12以外的其他文件名?

python fortran ctypes filestream fortran77
1个回答
2
投票

是的,它可以是内存映射文件,如下例所示。请注意,C部分来自我在StackOverflow上发现的示例,可能包含严重错误(它确实包含太多的类型转换),而且我不完全确定何时发生磁盘写入。但你肯定可以打开其他类型的文件,比如/dev/urandom甚至/dev/memnamed pipes,正如Steve在评论中提到的(Python示例如下)。

请注意,fd(c)或fileno(Python)与Fortran文件单元不同,不能以任何方式在Fortran中使用。

read_from_file.f90

      SUBROUTINE READER(IN,FVAL)
        IMPLICIT NONE
        INTEGER IN
        REAL FVAL
        PRINT *,'READER READING FROM',IN
        READ(IN,*) FVAL
        PRINT *,'READER DONE',FVAL
        RETURN
      END

implicit none

integer :: iu

character(256) :: fname
real fval
call get_command_argument(1,value=fname)
open(newunit=iu, file=fname,access="stream", form="formatted")

call READER(iu, fval)
print *,fval

close(iu)
end

mmap.c

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define SIZE 10

void* init(const char *file_path) {
    int fd = open(file_path, O_RDWR);

    if (fd < 0) {
        perror("Could not open file for memory mapping");
        exit(1);
    }

    int result = lseek(fd, SIZE-1, SEEK_SET);
    if (result == -1) {
        close(fd);
        perror("Error calling lseek() to 'stretch' the file");
        exit(EXIT_FAILURE);
    }

    result = write(fd, "", 1);
    if (result != 1) {
        close(fd);
        perror("Error writing last byte of the file");
        exit(EXIT_FAILURE);
    }    

    void *start_ptr = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    unsigned char *mem_buffer = (unsigned char *) start_ptr;

    if (mem_buffer == MAP_FAILED) {        
        exit(1);
    }

    printf("Successfully mapped file.\n");
    return start_ptr;
}

void unmap(void *start_ptr) {


    if (munmap(start_ptr, SIZE) < 0) {
        exit(1);
    }


    printf("Successfully unmapped file.\n");
}

int main(){
  char *ptr;
  ptr = (char *)init("test");
  strcpy(ptr,"42\n\0");
  system("./read_from_file test");
  strcpy(ptr,"258\n\0");
  system("./read_from_file test");
  unmap(ptr);
  return 0;
}

编译并运行

gfortran read_from_file.f90 -o read_from_file
gfortran  mmap.c

 ./a.out 
Successfully mapped file.
 READER READING FROM         -10
 READER DONE   42.0000000    
   42.0000000    
 READER READING FROM         -10
 READER DONE   258.000000    
   258.000000    
Successfully unmapped file.

Python管道示例:

import os

path = "/tmp/pipe"
os.mkfifo(path)
print(path+"\n")
fifo = open(path, "w")
fifo.write("345\n")
fifo.close()
os.remove(path)

壳1:

> python fifo.py
/tmp/pipe

shell 2:

>./read_from_file /tmp/pipe
 READER READING FROM         -10
 READER DONE   345.000000    
   345.000000    
© www.soinside.com 2019 - 2024. All rights reserved.