我正在寻找使用从基于文件的单元号读取的旧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
以外的其他文件名?
是的,它可以是内存映射文件,如下例所示。请注意,C部分来自我在StackOverflow上发现的示例,可能包含严重错误(它确实包含太多的类型转换),而且我不完全确定何时发生磁盘写入。但你肯定可以打开其他类型的文件,比如/dev/urandom
甚至/dev/mem
或named 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