在 Fortran 中将原始二进制文件读入数组的 EOF 处理
EOF handling for reading raw binary files into an array in Fortran
我正在尝试编写 Fortran 代码,以 64 字节的块读取原始二进制文件 [例如 .png],对其执行一些操作,然后可能将其写入另一个文件。目前我写的代码如下,借助:
写的
integer(kind = int8), dimension(0:63) :: file_read_buffer
integer :: input_file_handle
integer :: io_error
open(newunit=input_file_handle, file=input_file_name, status="old", access="stream", action="read", iostat=io_error)
if(io_error /= 0) then
! file didn't open properly
end if
do
read(unit = input_file_handle, iostat = io_error) file_read_buffer
select case(io_error)
case(0)
! consume buffer normally
case(iostat_end)
! do EOF processing
case default
! error!
end select
end do
如果在数组完全填满之前就达到了 EOF,有什么办法可以知道在达到 EOF 之前已经填满了多少?此外,如果 EOF 被引发一次,对 read() 的进一步调用是否也会 return EOF?
如果有帮助,我目前正在使用 gfortran。
如果 end-of-file 条件是由该输入语句引起的,则您无法确定该输入语句读取了多少。
但是,由于您的意图是使用该输入大小来处理缓冲区中已填充的部分,所以这不是问题:您 。也就是说,当触发 end-of-file 条件时,您的整个缓冲区将变为未定义。
相反,您应该丢弃整个缓冲区并重新处理输入。您有两个选择:
- 如果到达文件末尾,重新定位到文件末尾并读取更少的数据
- 确定剩余的数据量,如果可用的数据较少,则减少读取(避免 end-of-file 条件)
首先,如果您跟踪“成功”位置,则可以在失败时重新定位:
! Read full-sized chunks
do
read(unit, iostat=iostat) buffer
if (iostat==iostat_end) exit
inquire (unit, pos=file_pos)
end do
! reposition
read (unit, pos=pos)
! Read smaller chunks
do
read (unit, iostat=iostat) buffer(1)
if (iostat==isotat_end) exit
end
(处理在明显的地方进行。)这类似于 this other answer 中针对相关问题的想法。
对于第二个,使用文件位置及其大小我们可以查看是否有足够的“文件存储单元”来填充我们的缓冲区:
inquire (unit, size=file_size)
do
inquire (unit, pos=file_pos)
remaining = (file_size-file_pos+1)*FILE_STORAGE_SIZE/STORAGE_SIZE(buffer)
if (remaining<SIZE(buffer)) exit
read (unit) buffer
end do
read (unit) buffer(:remaining)
FILE_STORAGE_SIZE
告诉我们有多少位组成一个文件存储单元,STORAGE_SIZE
多少位存储(内存)一个元素数组。
第二个选项可能没问题,但一般来说并不安全:我们不能确定存储大小为 16 位的元素对应于 16 位文件存储单元。不过,这可能足以满足您的目的。并且您可以随时创建一个测试文件来查看您的缓冲区占用了多少个文件存储单元。
我正在尝试编写 Fortran 代码,以 64 字节的块读取原始二进制文件 [例如 .png],对其执行一些操作,然后可能将其写入另一个文件。目前我写的代码如下,借助
integer(kind = int8), dimension(0:63) :: file_read_buffer
integer :: input_file_handle
integer :: io_error
open(newunit=input_file_handle, file=input_file_name, status="old", access="stream", action="read", iostat=io_error)
if(io_error /= 0) then
! file didn't open properly
end if
do
read(unit = input_file_handle, iostat = io_error) file_read_buffer
select case(io_error)
case(0)
! consume buffer normally
case(iostat_end)
! do EOF processing
case default
! error!
end select
end do
如果在数组完全填满之前就达到了 EOF,有什么办法可以知道在达到 EOF 之前已经填满了多少?此外,如果 EOF 被引发一次,对 read() 的进一步调用是否也会 return EOF?
如果有帮助,我目前正在使用 gfortran。
如果 end-of-file 条件是由该输入语句引起的,则您无法确定该输入语句读取了多少。
但是,由于您的意图是使用该输入大小来处理缓冲区中已填充的部分,所以这不是问题:您
相反,您应该丢弃整个缓冲区并重新处理输入。您有两个选择:
- 如果到达文件末尾,重新定位到文件末尾并读取更少的数据
- 确定剩余的数据量,如果可用的数据较少,则减少读取(避免 end-of-file 条件)
首先,如果您跟踪“成功”位置,则可以在失败时重新定位:
! Read full-sized chunks
do
read(unit, iostat=iostat) buffer
if (iostat==iostat_end) exit
inquire (unit, pos=file_pos)
end do
! reposition
read (unit, pos=pos)
! Read smaller chunks
do
read (unit, iostat=iostat) buffer(1)
if (iostat==isotat_end) exit
end
(处理在明显的地方进行。)这类似于 this other answer 中针对相关问题的想法。
对于第二个,使用文件位置及其大小我们可以查看是否有足够的“文件存储单元”来填充我们的缓冲区:
inquire (unit, size=file_size)
do
inquire (unit, pos=file_pos)
remaining = (file_size-file_pos+1)*FILE_STORAGE_SIZE/STORAGE_SIZE(buffer)
if (remaining<SIZE(buffer)) exit
read (unit) buffer
end do
read (unit) buffer(:remaining)
FILE_STORAGE_SIZE
告诉我们有多少位组成一个文件存储单元,STORAGE_SIZE
多少位存储(内存)一个元素数组。
第二个选项可能没问题,但一般来说并不安全:我们不能确定存储大小为 16 位的元素对应于 16 位文件存储单元。不过,这可能足以满足您的目的。并且您可以随时创建一个测试文件来查看您的缓冲区占用了多少个文件存储单元。