Reputation: 55
I'm attempting to write Fortran code that reads a raw binary file [like a .png for example] in chunks of 64 bytes, performs some operations on it and then maybe writes it to another file. The code I have written so far is as follows, written with the help of this SO answer:
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
If EOF is reached before the array is completely filled, is there any way to know how much of it was filled before EOF was reached? Also, if EOF is raised once, will further calls to read() also return EOF?
I'm using gfortran at the moment if that helps.
Upvotes: 3
Views: 309
Reputation: 32366
You cannot determine how much was read by an input statement if an end-of-file condition is caused by that input statement.
However, as your intention is to use that input size to process just the part of the buffer that was filled, then that's not a problem: you cannot do that. That is, when an end-of-file condition is triggered your entire buffer becomes undefined.
Instead, you should throw away the entire buffer and reprocess the input. You have two options:
For the first, if you keep track of your "successful" position, you can reposition on failure:
! 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
(Processing goes in the obvious places.) This is similar to the idea present in this other answer for a related problem.
For the second, using the file position and its size we can see whether there are sufficient "file storage units" to fill our buffer:
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
tells us how many bits make up a file storage unit, and STORAGE_SIZE
how many bits to store (in memory) an element of the array.
The second option is possibly fine, but isn't really safe in general: we can't be sure that an element of storage size 16-bits corresponds to 16 bits of file storage units. This may, though, be good enough for your purposes. And you can always create a test file to see how many file storage units your buffer occupies.
Upvotes: 2