Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29236 Discussions

Write to a specific line and position on the line

Stuart_M_
Beginner
3,109 Views

Hi folks

I feel like this should be a piece of cake, but I'm stumped.

I want to write over the values of an input text file for a particular line number in the file, and if possible a particular position on that line. Any suggestions?

Thanks!

0 Kudos
8 Replies
Arjen_Markus
Honored Contributor II
3,109 Views

In general writing in an existing file will destroy that file.

The simplest and most robust solution is to write a copy of the file, inserting/substituting

the new values as you go along.

If the file can be treated as a direct-access (formatted) file you can in fact overwrite

parts of it without damaging the rest. But that is a tricky route: it requires that all

records as viewed by the program have the same length (if you are stubborn enough,

I guess you could open the file with a record length of 1, thus allowing you to rewrite

the file at the smallest granularity).

Regards,

Arjen

0 Kudos
Stuart_M_
Beginner
3,109 Views

I can write a copy of the input file no problem... but how do I replace specific, small parts of it, on various lines, with text from somewhere else. Each line contains multiple values corresponding with multiple parameters, but I only need to replace one value on a given line: how can I specify the position on the line to begin the write?

0 Kudos
Arjen_Markus
Honored Contributor II
3,109 Views

If I understand it correctly, you want to replace a piece of a string by another piece?

Something along these lines:

character(len=80) :: string, value

string = "PARAMETER1 # Value of parameter 1"

write( value, '(f10.4)' ) 3.45

string(1:10) = value

write( 10, '(a)' ) string

This would produce a line:

3.45 # Value of parameter 1

Is this what you want?

Regards,

Arjen

0 Kudos
Paul_Curtis
Valued Contributor I
3,109 Views
Quoting stubaan

I can write a copy of the input file no problem... but how do I replace specific, small parts of it, on various lines, with text from somewhere else. Each line contains multiple values corresponding with multiple parameters, but I only need to replace one value on a given line: how can I specify the position on the line to begin the write?

The level of file control you seek is straightforward, but mostly beyond the limited capabilities of Fortran file i/o (which is way behind the times, language-wise). If you are able to sacrifice portability for functionality, you can easily do all your file i/o using Win32 API functions which provide exactly the needed level of granular control. Here are some sample wrapper functions, which illustrate read/write operations wherein an arbitrary amount of data, denominated in bytes, can be positioned at any offset in the file:

[bash]SUBROUTINE rw_file (rwmode, ihandl, nbytes, loc_pointer, offset)
	IMPLICIT NONE
	CHARACTER(LEN=1), INTENT(IN)	:: rwmode
	INTEGER(HANDLE), INTENT(IN)     :: ihandl
	INTEGER, INTENT(IN)				:: nbytes, loc_pointer
	INTEGER, INTENT(IN), OPTIONAL	:: offset
	INTEGER							:: nact

	! position pointer if offset is provided
	IF (PRESENT(offset)) nact = SetFilePointer (ihandl, offset, NULL,FILE_BEGIN)

	IF (rwmode == 'R') THEN
		IF (.NOT.ReadFile (ihandl,			&  ! file handle
				     	  loc_pointer,		&  ! address of data
						  nbytes,			&  ! byte count to read
						  LOC(nact),		&  ! actual bytes read
						  NULL_OVERLAPPED))	THEN
		  	! read error
END IF ELSE IF (.NOT.WriteFile(ihandl, & ! file handle loc_pointer, & ! address of data nbytes, & ! byte count to write LOC(nact), & ! actual bytes written NULL_OVERLAPPED)) THEN !write error
END IF END IF END SUBROUTINE rw_file SUBROUTINE Set_File_Pointer (ihandl, offset, truncate) IMPLICIT NONE INTEGER(HANDLE), INTENT(IN) :: ihandl INTEGER, INTENT(IN) :: offset LOGICAL, INTENT(IN), OPTIONAL :: truncate INTEGER :: rslt rslt = SetFilePointer (ihandl, MAX0(offset,0), NULL, FILE_BEGIN) IF (PRESENT(truncate)) rslt = SetEndOfFile (ihandl) END SUBROUTINE Set_File_Pointer [/bash]

0 Kudos
Stuart_M_
Beginner
3,109 Views

Arjen, Paul - thanks for the assistance.

I originally began attempting this task in python, which I thought would be able to handle it without too much trouble. I have yet to get anywhere on this problem using python though.

That being said, I am obviously open to other options besides Fortran, though I frankly do not have the time to familiarize myself with another language right now - I have just spent three weeks trying to come to terms with DOS and BASH scripting as well as Python.

This is a link to the python forum I originally posted this question on - it contains the input file I am talking about as an attachment, and some conversation that clarifies just what I am trying to achieve.

http://www.daniweb.com/forums/post1120606.html#post1120606

I am very surprised by how seemingly difficult this is turning out to be - all I want is to be able to pinpoint a position in a text file, based on co-ordinates of line number and position on that line, and write the value of a variable over whatever is at that point.

0 Kudos
Paul_Curtis
Valued Contributor I
3,109 Views

"...all I want is to be able to pinpoint a position in a text file, based on co-ordinates of line number and position on that line, and write the value of a variable over whatever is at that point"

If each line (ie, record) in the file is the same length, presumably with a terminal , then any specific line+column location is a simple calculation of (n-1)*(recordlength + 2) + column_position, and you can simply open the file with that offset and (over)write as needed. In the more general case where the file has lines of varying length, again each with a terminal , the easy calculation will not work and you will have to read the entire file into a buffer array of records (ie, lines), find/change the substring of interest, and finally rewrite the entire file line by line, sending only the actual filled length of each record + .

0 Kudos
Les_Neilson
Valued Contributor II
3,109 Views
Quoting stubaan

I am very surprised by how seemingly difficult this is turning out to be - all I want is to be able to pinpoint a position in a text file, based on co-ordinates of line number and position on that line, and write the value of a variable over whatever is at that point.

declare variables to hold a datarecord and a record count

initialise the record count to zero

open the input file

open the output file

read a record from the input file into the datarecord

did we get end-of-file?

If "yes" then go to "done"

increment record counter

is this the record, or one of the records, we wish to modify?

if "yes" then

find in the data record the specificsubstring we wish to modify
(hint use INDEX? unlessyou already knowthe start and length/end position of the substring)
replace the substring of datarecord containing that data with the new data

endif

write the datarecord to the output file

go back and read the next datarecord

"done"

close both files

Les

0 Kudos
Arjen_Markus
Honored Contributor II
3,109 Views

Streams ought to solve the issue of positioning the file pointer anywhere in the file,

but that does not make the problem as such much easier: files nowadays are mostly

seen as a sequence of bytes, not of lines. So the basic problem remains: figuring

out where in the file the change should be made.

Regards,

Arjen

0 Kudos
Reply