Am I going bonkers...

BlitzMax Forums/BlitzMax Programming/Am I going bonkers...

col(Posted 2012) [#1]
Hiya,

I must be missing something obvious here.

I want to open a file, read a line of text then write a line of text. The following code will only successfully write the line "test me" into the file if I comment out the ReadLine line, even though the WriteLine returns as true ( successful ).

Can anyone enlighten me of my error?

Strict

Local _Stream = OpenFile("D:\TestFolder\test.txt") 'Default is Read and Write
Print ReadLine(_Stream)
WriteLine _Stream,"test me"
CloseFile _Stream


Last edited 2012


therevills(Posted 2012) [#2]
Im not on th PC right now but this is my guess, that ReadLine closes the steam?

Could you try the OpenFile again after the ReadLine?


Henri(Posted 2012) [#3]
Hello,
your example works fine for me if you specify type :Tstream for your local _Stream variable.

-Henri


Grey Alien(Posted 2012) [#4]
So that must mean it's defaulting to another type when not specified, weird.


col(Posted 2012) [#5]
Sorry guys, that's not the real app code, I wrote that for the forum.
The real stream variable is a TStream. Debugging through the BRLs code shows the stream is open successfully reading writing. But examining the file shows nothing has been written.


GfK(Posted 2012) [#6]
OK, here's what's happening, having tested it.

If I have a file containing the word "Hello" and nothing else, it works perfectly. If I have the same file with a linefeed after the "Hello", so the cursor is on the next line down, it fails.

This is probably a bug, since I would expect the "test me" text to be appended on the next line (i.e. after the linefeed). But that's not happening for some reason.

[edit] Without delving into the Blitzmax code, I wonder if it's because there are no printable characters at or after the file pointer, *and* it's not at the end of the file...

[edit again] Actually, much simpler explanation. WriteLine just fails if the file pointer is not at the end of the file. It does not seem to overwrite what's already there.

Last edited 2012


GfK(Posted 2012) [#7]
In addition, WriteLine does seem to be returning the correct True/False value here. Using Blitzmax 1.48, if it matters.


Midimaster(Posted 2012) [#8]
for the following test remove your test.txt and then run this code twice:

after the first run you will see, thatthe file is create with "first line". After the second run you will see, that there is no chance to add new lines after reading any line. You first have to close the file to overwrite the old line or you have to jump to the end of the file to add one line.

attention: I used "C:\temp...

[bbcode]SuperStrict

Global _Stream:TStream
Local FileName$="C:\Temp\test.txt"
'FileName="D:\TestFolder\test.txt"
If FileType(FileName)
_Stream = OpenStream(FileName)
Print ReadLine(_Stream)
Else
Print "as new!"
_Stream = WriteStream(FileName)
WriteLine _Stream,"first line"
CloseFile _Stream
End
EndIf

WriteLine _Stream,"error line"

SeekStream _stream, StreamSize(_stream)
WriteLine _Stream,"last line"

CloseFile _Stream
End
[/bbcode]


col(Posted 2012) [#9]
I get

first line
last line

in the file.

Ok, for testing, say my test file contains

First Line
Second Line
Third Line

I open the file and ReadLine which returns me 'First Line', I use WriteLine expecting it to overwrite Second Line, the WriteLine, including the BRL code returns values that it's been successful in writing the line but nothing is written.
Starting from scratch again with the 3 lines above, I open the file and WriteLine and it overwrites the FirstLine as expected.

So for some reason WriteLine after ReadLine fails although all code returns successful. If this isn't how things are expected to work then why do have separate flags in the OpenFile to allow reading and writing?

EDIT:- Some test code that hightlights the issue :-


I get :-
Testing ReadThenWrite
	OpenFile: OK
	ReadLine: FirstLine
	WriteLine: Writing "Testing" as a line: OK

	FileContents:
		FirstLine
		SecondLine
		ThirdLine

Testing WriteOnly
	OpenFile: OK
	WriteLine: Writing "Testing" as a line: OK

	FileContents:
		Testing
		
		SecondLine
		ThirdLine


I expect the empty line because of the difference in the number of chars in 'FirstLine' and 'Testing'. But anyway it still shows up the WriteLine failing to actually write the line and ReadLine.

Last edited 2012


col(Posted 2012) [#10]
...

Last edited 2012


Floyd(Posted 2012) [#11]
I think this comes down to having only one stream position for read and write. Let's say you read a line, then write a line ( at end of file ). If you now try another read where should it take place?

Here's a horribly hackish example of how I think it should work, using global variables just to illustrate how separate read and write positions could be maintained.

Starting with a text file containing these three lines:
one
two
three

This code will append lines "four" and "five".

Global fileStream:TStream = OpenFile( "textfile.txt" )

Global read_position = 0
Global write_position = StreamSize( fileStream )

Print ReadOneLine( )

WriteOneLine "four"

Print ReadOneLine( )

WriteOneLine "five"


CloseFile fileStream



Function ReadOneLine$( )
	Local read_txt$
	SeekStream fileStream, read_position
	read_txt = ReadLine( fileStream )
	read_position = StreamPos( fileStream )
	Return read_txt
End Function

Function WriteOneLine( txt$ )
	SeekStream fileStream, write_position
	WriteLine fileStream, txt$
	write_position = StreamPos( fileStream )
End Function



col(Posted 2012) [#12]
I've not tried your example as I'm not on the PC at the mo, but I would have thought the single stream position is the better way to go to give the expected operation. If you write at the end of the file then try to read I'd then expect an end of file situation, no?

If I remember from this morning from a glance into BRLs code.. the heart of it is pretty much a wrapper around the standard c fread and fwrite functions which according to the these links, the stream keeps its own internal position counter.

fwrite
fread

How bizarre!


Floyd(Posted 2012) [#13]
I came up with that after deciding that mixing readline and writeline was confusing the stream positioning.

My three line text file is 17 bytes, including three CR-LF endlines. After a Readline ( to get "one" and read past CR-LF ) StreamPos returned 5, as expected.

After that I tried a WriteLine to write the line "four". StreamPos then returned 11, as if the text had been written just after the first line with the rest of the file being ignored. Looking at the file in Notepad it seemed nothing had been written.

A little more experimenting showed that sometimes WriteLine fails. It returns a zero in this case. Instead of writing text to the end of the file it was just writing a CR-LF. This is why there was no obvious change visible in Notepad, although the file size had increased by two bytes.

That's when I quit trying and came up with my proposed solution/workaround.


col(Posted 2012) [#14]
Just found this -

from fopen

When a file is opened with update mode ( '+' as the second or third character in the mode argument), both input and output may be performed on the associated stream. However, the application shall ensure that output is not directly followed by input without an intervening call to fflush() or to a file positioning function ( fseek(), fsetpos(), or rewind()), and input is not directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.

BMax opens the file using the same update mode, so this explains it all.

@Floyd What would seem as a 'hacky' method of setting the stream position is the suggested method!

Thanks for all quick help guys!

Last edited 2012


TomToad(Posted 2012) [#15]
Here you go. This will use SeekStream() to set the file pointer to the current position. I tried FlushStream(), but it didn't work.



col(Posted 2012) [#16]
I tried also tried FlushStream. Maybe that's not for file streams. I came up with the same solution at the exact same place using SeekStream. It's an easy fix now that we know what the real issue is but I feel BRL should have really taken care of this inside the ReadLine and WriteLine functions. Oh well.

Thanks again for your help.

Edit:- Just for the record, FlushStream will work if you want to WriteLine then ReadLine, but you may as well use the SeekStream as it works for both writing then reading and reading then writing. All of this is because fopen, fclose, fread and fwrite etc use a buffer.

Last edited 2012