Writing <LF> into a data file

Writing into a data file

I have the following code which is supposed to write a <LF> between two text strings in the output file (which is a CSV file for reading into Excel):

n1 = '"'//trim(ndprops(1))//char(10)//trim(ndprops(2))//'",'

write(csvu,'(a)') trim(n1)

This is so that text too long for a cell is written on two lines into that cell.

However on examination of the file written, I see 0d0a so that an extra <CR> is written to the file, which means the line is read incorrectly into Excel.

How do I tell Fortran not to write the 0d?

21 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.
Steve Lionel (Intel)'s picture

Open the file access='stream'. Then only the bytes you write are written. You'll need to write your own record terminators if you want them.

Steve

I tried this:

   el = char(13)//char(10)

   open(unit=csvu, file=trim(arg)//'.csv', status='unknown', access='stream', iostat=ierr,err=999)

   write(csvu,'(a)') 'Branch Data'//el

and I got:

forrtl: severe (257): formatted I/O to unit open for unformatted transfers, unit 14, file tee2hor.csv

I guess it's a formatted / unformatted issue?

Try:

 write (csvu) 'Branch Data'//el

If that does not work, copy 'Branch Data'//el into a character variable and then write one character at a time.

character string*80

	...

	string = 'Branch Data'//el

	do i = 1, len_trim (string)

	 write (csvu) string(I:i)

	end do

I have always found reading or writing single characters to stream I/O to have few problems, so I'd expect the first option to work.
stream I/O can be a simple and effective solution, although standard text files for .csv files should be all that is needed.

John

I tried that but I'm still getting 0d0a written to the CSV file instead of just 0a (between brprops(1,i) and brprops(2,i))

          write(csvu) 'Branch Data'//el
          write(csvu) (trim(b1(i)), i=1, nbrprop),'""'//el

where:

          b1(i) = '"'  //trim(brprops(1,i))//char(10)//trim(brprops(2,i))//'",'

 

jimdempseyatthecove's picture

>>I tried that but I'm still getting 0d0a written to the CSV file instead of just 0a

 el = char(13)//char(10)

What do you expect when the character stream written is instructed to insert 0d0a?

If you want only 0a, then use only char(10) in one character variable.

Jim Dempsey

www.quickthreadprogramming.com
mecej4's picture

Adrian F: Please see section 9.3.3.4 of the Fortran 2008 standard. Stream files can be opened in formatted or unformatted mode, and the rules governing formatted mode may make it less suited to your needs. 

Here is code that works with Ifort, Gfortran and NAG:

 character*2 el

	 character*15 line

	 integer csvu

	!

	 el = char(13)//char(10)

	 csvu=11

	 open(unit=csvu, file='csvu.csv', status='unknown', access='stream', iostat=ierr,err=999)

	 write(line,'(a)') 'Branch Data'//el

	 write(csvu)line

	 stop

	 999 write(*,*)' Error in opening csvu.csv'

	 end

Note that the file is opened with FORM='UNFORMATTED' by default when ACCESS='STREAM' is used. To overcome the problem that you encountered by attempting formatted I/O to such a stream, I write to a character variable long enough to hold the output of the WRITE, then I write the character variable to the file.

I realize that making such changes to a large program will involve considerable effort. Please consider whether the RECORDTYPE='STREAM_LF' specifier, used in combination with formatted output, will better serve your purposes.

If I set el = char(10) in the fifth line (not counting the forum-software-donated blank lines) instead, the output CSV file contains no CR characters at all, and that is the behavior that you sought.

you're misquoting me...

I am trying to write string1//char(10)//string2, but I'm getting string1 0d 0a string2 in the data file

el (0d0a) is written at the end of the line
 

I think the easiest way is to write the file in the normal way and to write some special character instead of char(10) and then to post process the file by replacing all these special characters with char(10)

app4619's picture

so as in mecej4's post where he has:

write(line,'(a)') 'Branch Data'//el

you should put

write(line,'(a)') 'a string'//char(10)//'another string'//char(13)//char(10)

 

mecej4's picture

Quote:

Adrian F. wrote:

I think the easiest way is to write the file in the normal way and to write some special character instead of char(10) and then to post process the file by replacing all these special characters with char(10)

I have used that artifice several times in the past for writing CSV files-- not  for use in Excel but for inputting data to an SQL database. You will have to choose a special character, such as '$', which you can be reasonably sure to not occur in any of your string data. Utilities such as tr can do the routine transliteration for you, but context-dependent substitutions will need more work by the user to ensure that incorrect and irreversible substitutions are not made.

Now I'm confused.  I am writing '#' into the output file where I eventually want char(10).  After I'm finished writing the file, I execute the following code to read from this file one char at a time and write into the new file, substituting '#' with char(10):

        ll = len_trim(fil)-1
        open(unit=csvu, file=trim(fil)     , status='unknown', access='stream', iostat=ierr,err=999)
        open(unit=csvv, file=fil(1:ll)//'v', status='unknown', access='stream', iostat=ierr,err=999)
        do while (.not. eof(csvu))
          read(csvu) c1
          if(c1 == '#') c1 = char(10)
          write(csvv) c1
        enddo
        close(unit=csvu)
        close(unit=csvv)

However when I look into the new output file I still see 0d0a instead of just 0a !  Where is this other 0d coming from ??

mecej4's picture

Quote:

Adrian F. wrote:
Where is this other 0d coming from ?

It is hard to say, without seeing the hex-dump of the input file. I tried your code on an input file, x.csu, with the following contents:

s:lang>xxd x.csu

	0000000: 4272 616e 2368 2044 6174 610a 200a       Bran#h Data. .

Here is the dump of the output file (on Windows 8.1-64):

s:lang>xxd x.csv

	0000000: 4272 616e 0a68 2044 6174 610a 200a       Bran.h Data. .

s:lang>fc/b x.csu x.csv

	Comparing files x.csu and X.CSV

	00000004: 23 0A

The two files are attached.

Attachments: 

AttachmentSize
Download tee2hor.txt2.44 KB
Download tee2hor_new.txt2.44 KB
mecej4's picture

The input file tee2hor.txt has <CR> characters in it. I removed them using the dos2unix utility that is available for Cygwin, and ran the program that you listed in #12 on it. I found that the output file had all instances of '#' replaced by <LF>, and there were no <CR> characters in the output file. Thus, everything appears to be in proper order.

I'm not sure which <CR>'s you are seeing.  It is the # between say "defined" and "start node" (ie. defined#start node) which I'm trying to replace by <LF>.  tee2hor.txt has the #.  I'm not talking about the <CR><LF> at the end of the line.  Those are the only <CR> in the file.  eg. The first line of tee2hor.txt looks as follows:

"  number","  name","  type","defined#start node","defined#end node","flow#start node","flow#end node","roughness#(mm)","length#(m)","diameter#(mm)","kfitting#method","fitting#k1","fitting#kinf","angle#(deg)","Darcy#fric factor","inlet#pressure (bar)","outlet#pressure (bar)","inlet#temperature (C)","outlet#temperature (C)","friction#velocity head","fittings#velocity head","momentum#velocity head","density#(kg/m3)","viscosity#(cP)","heat cap#(kJ/kgK)","velocity#(m/s)","Reynolds#number","flowrate#(kg/s)","frictional#deltap (bar)","elevational#deltap (bar)","tee#deltap (bar)","total#delta p (bar)","flow#direction","tear#branch","spec#type","  text",""<CR><LF>

I'm looking to replace all the # in the line by <LF> by my code.  I have attached the output file created by my code which as you can see has <CR><LF> where the #'s were

Actually I just looked at the output file using XXD and it does have the <LF> only, it must be my editor (Crisp) which is adding the <CR> !

Anyways, that said, when I try to import this output file into Excel, I still have the same problem that the items separated by this <LF> do not appear on separate lines in the same cell.  In fact the second bit after the <LF> is ignored and not imported.

Any idea How I can get, eg.

defined
start node

in one cell?

app4619's picture

This program forms the output with LF and CR in the correct places, I tested with excel 2003?

    program Console3

	        implicit none

	        character(len=64000)         :: gbuf

	        integer                      :: ip, istat

	        character(len=256)           :: gstuf

	        ip=1

	        gstuf='Branch Data'

	        call addstring(gbuf,ip,gstuf,2)

	        gstuf='"  number","  name","  type","defined'

	        call addstring(gbuf,ip,gstuf,1)

	        gstuf='start node","defined'

	        call addstring(gbuf,ip,gstuf,1)

	        gstuf='end node","flow'

	        call addstring(gbuf,ip,gstuf,1)

	        gstuf='start node"'

	        call addstring(gbuf,ip,gstuf,2)

	        gstuf='1,"B1","PIPE","N1","N3","N1","N3",  0.45700000E-01,   100.00000    ,   100.00000    ,1,   0.0000000    ,   0.0000000    ,  0.000,'

	        call addstring(gbuf,ip,gstuf,2)

	        open(10,file='fred.csv',status='unknown',access='stream',iostat=istat)

	        if(istat /= 0) write(*,*) 'open error'

	        write(10,iostat=istat) gbuf(1:ip-1)

	        if(istat /= 0) write(*,*) 'write error'

	        close(10,iostat=istat)

	        if(istat /= 0) write(*,*) 'close error'

	        write(*,*) 'Finished'

	    end program Console3

	    subroutine addstring(gbuf,ip,gstuf,ifl)

	        character(len=2),parameter   :: LF=char(10)

	        character(len=2),parameter   :: CR=char(13)

	        character(len=2),parameter   :: CRLF=char(13)//char(10)

	        character(len=*), intent(inout) :: gbuf

	        integer, intent(inout)          :: ip

	        integer, intent(in)             :: ifl

	        character(len=*), intent(in)    :: gstuf

	        integer                         :: ilen

	        ilen=len_trim(gstuf)

	        gbuf(ip:ip+ilen-1)=gstuf(1:ilen)

	        ip=ip+ilen

	        if (ifl==2) then

	            gbuf(ip:ip)= CR

	            ip=ip+1

	        else

	            gbuf(ip:ip)= LF

	            ip=ip+1

	        endif

	    end subroutine addstring

app4619's picture

That was the output in excel attached (screen grab)

Attachments: 

AttachmentSize
Download Capture_1.GIF13.66 KB

I ran your program above and it created the fred.csv attached (I had to rename to .txt as the forum's uploader wouldn't allow.csv files ??).

Then I imported into Excel 2010, but I still have the same problem, see attached screen capture.

Attachments: 

AttachmentSize
Download Snap1_0.jpg49.39 KB
Download fred.txt229 bytes

Actually it does work, just that you have to turn on Word Wrap in Excel!  My original format worked too...

Login to leave a comment.