way to big to use allocatable arrays.
If the data fits in memory, you can do it. I've tested it out, a file
header(1)
header(2)
header(3)
block(1).data1 block(1).data2 block(1).data3
block(1).data4 block(1).data5 block(1).data6
block(2).data1 block(2).data2 block(2).data3
block(2).data4 block(2).data5 block(2).data6
...
block(9999998).data1 block(9999998).data2 block(9999998).data3
block(9999998).data4 block(9999998).data5 block(9999998).data6
block(9999999).data1 block(9999999).data2 block(9999999).data3
block(9999999).data4 block(9999999).data5 block(9999999).data6
with a file size of 1.2GB could be reversed by this little awk script:
#!/usr/bin/awk
# if line contains word "header", print immediately, move on to next line.
/header/ {print; next}
# move every line to memory.
{
line[n++] = $0
}
# When finished, print them out in order n-1, n, n-3, n-2, n-5, n-4, ...
END {
for (i=n-2; i>=0; i-=2) {
print(line[i])
print(line[i+1])
}
}
in under 2 minutes.
If this is really not possible, you need to do what @high-performance-mark said and read it in in blocks that are manageable, reverse it in memory, then concatenate them together at the end. Here's my version:
program reverse_order
use iso_fortran_env, only: IOSTAT_END
implicit none
integer, parameter :: max_blocks_in_memory = 10000
integer, parameter :: max_line_length=100
character(len=max_line_length) :: line
character(len=max_line_length) :: data(2, max_blocks_in_memory)
character(len=*), parameter :: INFILE='data.txt'
character(len=*), parameter :: OUTFILE='reversed_data.txt'
character(len=*), parameter :: TMP_FILE_FORMAT='("/tmp/", I10.10,".txt")'
character(len=len("/tmp/XXXXXXXXXX.txt")) :: tmp_file_name
integer :: in_unit, out_unit, tmp_unit
integer :: num_headers, i, j, tmp_file_number
integer :: ios
! Open the input and output files
open(newunit=in_unit, file=INFILE, action="READ", status='OLD')
open(newunit=out_unit, file=OUTFILE, action='WRITE', status='REPLACE')
! Transfer the headers to the output file immediately.
num_headers = 0
do
read(in_unit, '(A)') line
if (index(line, 'header') == 0) exit
num_headers = num_headers + 1
write(out_unit, '(A)') trim(line)
end do
! We've already read the first data line, so let's rewind and start anew.
rewind(in_unit)
! move past the headers.
do i = 1, num_headers
read(in_unit, *)
end do
tmp_file_number = 0
! Read the data from the input line max_blocks_in_memory blocks at a time.
read_loop : do
do i = 1, max_blocks_in_memory
read(in_unit, '(A)', iostat=ios) data(1, i)
if (ios == IOSTAT_END) then ! Reached the end of the input file.
if (i > 1) then ! Still have final values in memory, write them
! to output immediately.
do j = i-1, 1, -1
write(out_unit, '(A)') trim(data(1, j))
write(out_unit, '(A)') trim(data(2, j))
end do
end if
exit read_loop
end if
read(in_unit, '(A)') data(2, i)
end do
! Reasd a block of data, write it in reverse order into a temporary file.
tmp_file_number = tmp_file_number + 1
write(tmp_file_name, TMP_FILE_FORMAT) tmp_file_number
open(newunit=tmp_unit, file=tmp_file_name, action="WRITE", status="NEW")
do j = max_blocks_in_memory, 1, -1
write(tmp_unit, '(A)') data(1, j)
write(tmp_unit, '(A)') data(2, j)
end do
close(tmp_unit)
end do read_loop
! Finished with input file, don't need it any more.
close(unit=in_unit)
! Concatenate all the temporary files in reverse order to the output file.
do j = tmp_file_number, 1, -1
write(tmp_file_name, TMP_FILE_FORMAT) j
open(newunit=tmp_unit, file=tmp_file_name, action="READ", status="OLD")
do
read(tmp_unit, '(A)', iostat=ios) line
if (ios == IOSTAT_END) exit
write(out_unit, '(A)') trim(line)
end do
close(tmp_unit, status="DELETE") ! Done with this file, delete it after closing.
end do
close(unit=out_unit)
end program reverse_order