Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Reading from file error

Status
Not open for further replies.

ibjeremy

Programmer
Jan 20, 2004
4
US
Programming in Turbo Pascal 7, I'm using the following code:

Code:
(*********************************************************)
procedure InputData ( var DataFile : text; var Collection : MagicCardCollection; var EntryCount : integer);


Begin
  EntryCount:=0;
  reset (DataFile);

  while (not (EOF(DataFile))) do
    begin

      Inc(EntryCount);

      with (Collection[EntryCount]) do
        begin
          readln (DataFile,Name);
          readln (DataFile,Artist);
          readln (DataFile,Effect);
          readln (DataFile,Rarity);
          readln (DataFile,SetName);
          readln (DataFile,Legality);
          readln (DataFile,CardType);
          readln (DataFile,FlavorText);
          readln (DataFile,Color);
          readln (DataFile,Power);
          readln (DataFile,Toughness);
          readln (DataFile,ManaCost);
          readln (DataFile,Quantity);
          readln (DataFile,Price);
        end;

    end;
    close (DataFile);
End;
(********************************************************)

Through echo checking, I find that the loop works fine for 20 or less iterations. However, at the 21st iteration, I recieve an error at the line "
Code:
readln(DataFile,Color)
". The error says "File not open for input", even though it was been reset before the loop, and there is no close command until after the loop. Is there perhaps a limit to the amount of reading that you're allowed to do from a file in one go?
 
There's no limit on the number of readlns from a text file.
Try to step through it and put a watch on DataFile to see when it changes its status from "input" to "closed".

Some questions:
Are you accessing the file from within some other application at the same time?
What are the types of the members of MagicCardCollection? If they're not all strings, you can get into trouble when reading text if an integer was expected.
You have no range check on EntryCount, what if there is more text in the file than there are slots in the array?
What if the number of lines in the file is not a multiple of the number of fields in a card record? The last entry in the array will be incomplete.
This is a nice example of reading records of data, so why not use record files? You then only need one read operation to read an entire record and you don't have to convert strings to other data, you can read enum values and you can read sets.

Example:
Code:
TYPE Tcolor = (red,green,blue);
     card = record
              name : string[30];
              color : Tcolor;
              price : word;
            end;
VAR f : file of card;

while not eof(f) do
begin
  {$I-} read(f,collection[count]); {$I+}
  if ioresult<>0 then error in file
  inc(count);
end;

Regards,
Bert Vingerhoets
vingerhoetsbert@hotmail.com
Don't worry what people think about you. They're too busy wondering what you think about them.
 
I'd like to avoid using a file besides text type for my own reasons. The text file being read is asurdily correct in it's format, the fields being in groups of 14. There in to &quot;Invalid numeric format&quot; error.

I have tried finding the EntryCount in another procedure, the using a for loop instead of a while loop, but I recieve the same error. The problem at hand is finding out why the file is seen as closed when it has bene reset before, and a close command has not yet been encounterd.

If all else fails, I will try to switch over to using a file of the record. Thanks for your suggestions, though.
 
Two thoughts.
(1) Sorry, this is a bit of a silly one, but worth checking: when you say the fields are in groups of 14, yes, good, they must be. But remember that readln can happily read an empty line, and always reads a complete line, so what you must have is a text file where each line corresponds to a single item from &quot;collection&quot;, i.e. &quot;name&quot; is on a different line to &quot;artist&quot;; and the whole file must contain a number of lines exactly divisible by 14, with no extra blank lines at the end (i.e. it is very important whether you pressed the enter key in your text editor at the end of the last line!)
(2) readln will read up to 255 characters of text into the contents of each thing in collection, and I think it will do so irrespective of how long a string you actually allocated (depending on compiler directives/options). Do check that no line is longer than the space allocated. If it is, it will overwrite things. If you're really unlucky it overwrote the text file variable, which means that next time you tried to read from that text file, you were reading from some other text file that wasn't open...

A good process for error checking is to get it to print out the items it's found on the 20th loop, with an extra character at the start and finish so you can see how long the line was (i.e. did it have 35 spaces at the end inserted by the text editor for some reason, that you can't see, but are overwriting something).
 
Yup, I notice the error occured after 288 reads, which is 18 lots of 16. How many complete &quot;collections&quot; are you expecting in your file?
 
Reading past the end of a text file is no problem, when reading a string, the result will be the empty string; when reading integers, the result will be 0 and when reading floating point types, the result will be 0.0.
Furthermore, when a line is too long to be read entirely, the only logical result that can be thought of is that the excess characters are loaded in memory following the memory location in which the legal part is stored (i.e. when the line for &quot;name&quot; would be too long, the excess characters would be loaded in the &quot;artist&quot; field, not in the text file variable). In reality, however, TP takes care of lines that are too long and just discards of the excess of characters.

What I would like to see is the declaration of magiccardcollection (and the record). I would also like to know what happens with the text file variable: does it just switch status from &quot;input&quot; to &quot;closed&quot; or is it completely scrambled? (in the latter case the memory of the text file variable is somehow overwritten). To check this, place a break line in the loop (with condition entrycount = 21) and a watch on datafile.

I still advise you to use record files; you don't have to do parsing, you can read and write all types of variables and you save valuable memory.

Regards,
Bert Vingerhoets
vingerhoetsbert@hotmail.com
Don't worry what people think about you. They're too busy wondering what you think about them.
 
Sorry, I'm writing rubbish, but I'm just stretching my imagination to work out what might be going wrong because I'm running out of ideas. You aren't calling any of your own procedures or functions so there is nothing else that could be closing the file, so the file variable itself must be getting scrambled some way. What about the size of the array of collections? Is it big enough?
Bert, what do all the &quot;var&quot;s in the procedure line do? My experience is with turbo 6.0, and I've never used them there. My procedure would have been
procedure name(varname : vartype)
not procedure name (var varname : vartype)
??
Thanks!
 
Var means that a pointer is put on the stack in stead of a copy of the whole structure. As a result, changes to the structure from within the procedure will also be applied to structure that was passed.

Example:
Code:
procedure test(s1 : string; var s2 : string);
begin
  s1:='one';
  s2:='two';
end;

procedure main;
var s1,s2 : string;
begin
  s1:='';
  s2:='';
  test(s1,s2);
end;

At the end, s1 will contain '' and s2 'two'.

Regards,
Bert Vingerhoets
vingerhoetsbert@hotmail.com
Don't worry what people think about you. They're too busy wondering what you think about them.
 
Thanks! Useful thing to know. And to think all these years I've been passing addresses explicitly and casting types at the other end. Daft as a brush.
I still agree I'd love to see the type definition of magiccardcollection.
 
Well, I never could figure out what was wrong, so I changed the structure of my program to use a record file.

To anyone still interested in figuring out why this ever happened:

The file was generated by the program, so there shouldn't have been any problem with reading extra stuff. I made sure all the lines were short enough, held the correct data, and there were no extra lines betwen entries. When I had 21 entries, the command directly before
Code:
 readln (DataFile,Color);
worked perfectly fine (I echo checked the value). Here is the declaration for the type OneMagicCard:

Code:
type

  ShortString = string[35];

  OneMagicCard = record

    Name,                   
    Color,
    Artist,                
    Effect,                
    Rarity,               
    SetName,              
    Legality,            
    CardType,            
    FlavorText  : ShortString;    

    Power,      
    ManaCost,   
    Quantity,   
    Toughness   : byte;  

    Price       : real;  
                                                  
  end;
 
The only thought left in my head, and it's really unlikely, is that somehow you messed up the stack somewhere. You can get weird file-not-open errors off readln, even a readln from keyboard with no file involved at all, if you've pushed and popped and got stuff on the stack that readln can't interpret (been there, done that, feel embarassed about it).
But usually this can only be done if you're mixing asm and pascal.
 
Well, I finnaly found out where the place the error originated; it all stemmed from a typo in a constant.

Instead of the maximum array size being set to 200, it was set to 20; this explains the error on the 21st iteration.

The moral of the story is...if all logic is defied, it must be a typo.
 
Ha! Actually not so illogical after all. You must have overwritten the file variable when you overshot your array.
Thanks lots for telling us the answer. Much appreciated.

 
It can be helpful sometimes to switch on range checking when debugging programs: {$R+}

Regards,
Bert Vingerhoets
vingerhoetsbert@hotmail.com
Don't worry what people think about you. They're too busy wondering what you think about them.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top