I have a Fortran program which reads data from a bunch of input files. The first file contains, among other things, the names of three other files that I will read from, specified in the input file (which I redirect to stdin at execution of the program) as follows
"data/file_1.dat" "data/file2.dat" "data/file_number_3.txt"
They're separated by regular spaces and there's no trailing spaces on the line, just a line break. I read the file names like this:
character*30 fnames(3)
read *, fnames
and then I proceed to read the data, through calling on a function which takes the file name as parameter:
subroutine read_from_data_file(fname)
implicit none
character*(*) fname
open(15,file=fname)
! read some data
end subroutine read_from_data_file
! in the main program:
do i=1,3
call read_from_data_file(trim(fnames(i)))
end do
For the third file, regardless of in which order I put the file names in the input file, the padding doesn't work and Fortran tries to open a with a name like "data/file_number_3.txt ", i.e. with a bunch of trailing spaces. This creates an empty file named data/file_number_3.txt (White Space Conflict) in my folder, and as soon as I try to read from the file the program crashes with an EOF error.
I've tried adding trim() in various places, e.g. open(15,file=trim(fname)) without any success. I assume it has something to do with the fix length of character arrays in Fortran, but I thought trim() would take care of that - is that assumption incorrect?
How do I troubleshoot and fix this?
Hmmm. I wonder if there is a final character on the last line of your input file which is not whitespace, such as an EOF marker from a Linux system popping up on a Windows system or vice-versa. Try, if you are on a Linux box, dos2unix; on a Windows box try something else (I'm not sure what).
If that doesn't work, try using the intrinsic IACHAR function to examine each individual character in the misbehaving string and examine the entrails.
Like you, I expect trim to trim trailing whitespace from a string, but not all the characters which are not displayed are regarded as whitespace.
And, while I'm writing, your use of declarations such as
character*30
is obsolescent, the modern alternative is
character(len=30)
and
character(len=*)
is preferred to
character*(*)
EDIT
Have you tried both reading those names from a file and reading them from stdin ?
Related
I'm writing a script that at one point needs to remove a literal string (no regex matching needed) from a file. Both the string and file path are in script variables.
The problem is that the string is multi-line, and may also contain special characters. Additionally, not all lines in the string are unique in the file (but the string as a whole is), so I cannot go line by line to delete each individual one from the file.
For example, when I echo "$stringToDelete" from my script I get something like:
values(
/the/#quick/[]/"fox",
//jumped/over/the,
//lazy/{},
)
I've tried some approaches using sed and awk but any attempt fails with issues around either the newlines or the special characters. I've seen some answers invoking perl but couldn't get that to work.
Also I can easily read the full file's content into a variable, so the solution doesn't need to edit the file directly - a way to remove the stringToDelete from another string var is fine too.
The title is not really specific, but I have trouble identifying the correct key words as I'm not sure what is going on here. For the same reason, it is possible that my question has a duplicate, as . If that's the case: sorry!
I have a Linux application that receive data via flat files. I don't know exactly how those files are generated, but I can read them without any problem. Those are short files, only a line each.
For test purpose, I tried to modify one of those files and reinjected it again in the application. But when I do that I can see in the log that it added a mysterious page break at the end of the message (resulting in the application not recognising the message)...
For the sake of example, let's say I receive a flat file, named original, that contains the following:
ABCDEF
I make a copy of this file and named it copy.
If I compare those two files using the "diff" command, it says they are identical (as I expect them to be)
If I open copy via Vi and then quit without changing nor saving anything and then use the "diff" command, it says they are identical (as I also expect them to be)
If I open copy via Vi and then save it without changing anything and then use the "diff" command, I have the following (I added the dot for layout purpose):
diff original copy
1c1
< ABCDEF
\ No newline at end of file
---
.> ABCDEF
And if I compare the size of my two files, I can see that original is 71 bytes when copy is 72.
It seems that the format of the file change when I save the file. I first thought of an encoding problem, so I used the ":set list" command on Vim to see the invisible characters. But for both files, I can see the following:
ABCDEF$
I have found other ways to do my test, But this problem still bugged me and I would really like to understand it. So, my two questions are:
What is happening here?
How can I modify a file like that without creating this mysterious page break?
Thank you for your help!
What happens is that Vim is set by default to assume that the files you edit end with a "newline" character. That's normal behavior in UNIX-land. But the "files" your program is reading look more like "streams" to me because they don't end with a newline character.
To ensure that those "files" are written without a newline character, set the following options before writing:
:set binary noeol
See :help 'eol'.
At the begining, I'd like to say that I'm very beginer with linux and stuff.
I'm reading a file (line by line) with use of a GetLine.
At the start, I open file descriptor with function open.
Then I change (int)f_descriptor to (FILE*)f_stream (because GetLine requires FILE* arg).
I'm splitting whole line into words (space is a separator) and I place them into a char** words_array. Everything works Ok as long as it's not the last word in the line. For some reason, last words have got some strange chars at the end of them. It doesnt happen always.
Why could this happen?
By the look of things, I suspect you're not null-terminating the last string. The length it's reporting is correct, but the fact that you've got extra bytes might mean that you're copying things into an area of memory that has some, but not all, null bytes in it initially but you're not adding an explicit null byte. If you want a better answer it will help if you can post some of the code where you're reading the data.
You can't simply change an (int) f_descriptor into a (FILE*) f_stream. They're two very very different things. If you use open() to get f_descriptor, you need to use read() and write() to access the file, but if you use fopen() to get f_stream, you use fgetch(), fread(), fwrite(), gets(), puts(), fprintf(), fscanf(), etc.
I have a piece of Fortran code:
C --------------------------------------------
CALL READIN_HYD
CALL READIN_CONFIG
CALL READIN_FORCE
CALL READIN_STEPPER
C --------------------------------------------
OPEN(11,FILE='EVO_0wall.dat')
and I'm attempting to replace the hardcoded file name (EVO_0wall.dat) with something I can input from my input parameters (which are all read by the subroutines readin_hyd, etc).
I'm trying to do something like this:
CHARACTER*30 OUTFILE
WRITE(*,*) 'OUTPUT FILE'
READ(*,*) OUTFILE
WRITE(*,*) 'OUTPUT FILE: ',OUTFILE
which I have added into the READIN_CONFIG subroutine. Coming back, I replace with
OPEN(11,FILE=OUTFILE,STATUS='NEW')
in the main routine in the hope that it will say the same thing as before if the input file I pipe in contains 'EVO_0wall.dat' (with the apostrophes) in the appropriate place.
If I run the code, all other input variables are read correctly, and the data is output correctly - however, it creates and places the output in an odd file with no extension and broken characters for a name (for example, degree, "{a}, and 0 ). Renaming the file with a .dat extension lets me open it, and the data within is correct. (edit: actually, the variable OUTFILE changes to the odd characters when its in the main function, if I try to simply print its value, so I guess its not just wrong syntax in the OPEN statement)
Is there some way that Fortran handles strings that I'm missing between these? I'm afraid I'm a novice to Fortran (this is someone else's code that I'm adapting), and am not quite sure what I'm missing. Any help would be much appreciated!
Thanks!
As an alternative to the suggestion of #M.S.B., you may use trim and adjustl, like this:
implicit none
character*99 :: outf
outf='outf.outf'
open(1,file=trim(adjustl(outf)))
write(1,*)'foobar',42
close(1)
end
Here adjustl ensures that there's no leading whitespace, and trim trims the trailing whitespace. This should work as long as the outf variable only contains legal characters [I'd suggest using basic ASCII only].
On a side note, if I add status='new' to the open statement, it fails at runtime (with gfortran 4.4.3 at least) if the file already exists. If you really want to make sure that the existing file is not overwritten, you need to inquire first.
That seems OK. The following read statement should allow you to omit the apostrophes:
read (*, '(A)' ) outfile
What does the "echo" write statement of the value of outfile output?
My FORTRAN is rusty, but I think the {a} may represent hex A, or decimal 10, which is a newline. That's what you would get when you read in the OUTFILE name.
You may need to TRIM the OUTFILE of all whitespace
here is the trouble ... i'm dynamically building (rather changing)a string which contains numerals(numbers) (like to have filename out01.txt ,out02.txt etc ..)
my program works fine (i'm using the last updated value string to name a file and edit that file) ... but in the same directory with "ls" command, i can see that file created and through file browser i can acess it but from command line using vim , gedit i can't open it new file of same name is opening... moreover i can't remove that file from command line (rm out010.txt'
no such file or directory) here is the code , i might not have been able to explain my problem but code will speak for itself ...
program strtest
implicit none
character(len=1024)::filen,format_str
integer::i
format_str="(a5,i0.3,'.txt')"
do i=1,10
write(filen,format_str)'out',i
end do
write(*,*)trim(filen)
open(23,file=trim(filen))
write(23,*)"what a mess!"
close(23)
stop
end program strtest
note: i have the same problem even without using trim() function in file opening statement
please explain my situation!!
regards ...
Your filenames are coming out with 2 spaces in front of them, so if you put rm " out01.txt" (2 spaces,out01.txt) you will be able to delete them. It's the a5 that's throwing off the format string.
As #jonsca pointed out already, the problem is with the extra whitespace. The simplest way to get rid of it is to use adjustl, like this:
open(23,file=trim(adjustl(filen)))