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 IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Too many open files

Status
Not open for further replies.

Antagonist

Programmer
Jan 19, 2004
2
AU
I'm writing a program at the moment in TP 7 and have come across a problem. The program is a translation quiz, where it asks for translations from one language to another.

At the moment i get the information for the questions from one file (at random) and the answers from another, which are then written to temporary variables.

I'm opening and closing the same 2 files over and over, as they are part of a repeat loop. But i find that when it tries to open the files for 15th file i get the Error 4 message: Too many open files.

So basically, in order to prevent writing more code, and make the program more difficult to add words to later, i'm wondering if there is a way to constantly read from a file without crashing the program. I mean i'd be probably looking to open these files up to 200 times per running.

Each time i read from the files, i read a random line, and lets say there could be 500 lines (words) in the file (at the moment there are 10), i don't want to declare 1000 constants.

I'm new it this, there may be an easy way around this, if so i'm all ears :>

Åñt

{ file1,file2,qstring,astring,answer:string }

Procedure DutchVocab;

Begin
ClrScr;
file1:= 'C:\TK\Dutch.txt';
file2:= 'C:\TK\English1.txt';
Writeln;
Write ('How many words to practice? ');
readln (Qlast);
Q:=0;
score:=0;

ClrScr;
Repeat
ClrScr;
Randomize;
RanVal:=Random(10);


Assign (input,file1);
reset (input);
line:=0;
Repeat
Readln (Qstring);
line:=line+1;
until line = RanVal;
close (input);
assign (input,'con');
reset(input);

Assign (input,file2);
reset (input);
line:=0;
Repeat
Readln (Astring);
line:=line+1
until line = RanVal;
close (input);
assign (input,'con');
reset(input);

Q:=Q+1;
Writeln ('Translate the following into English');
Writeln;Writeln;
Writeln (Qstring);
Writeln;
Write ('=> ');
readln (Answer);
If Answer = Astring then begin
Writeln;
Writeln ('Correct!');
score:=score+1;
delay (3000);
end

else begin
Writeln;
Writeln ('Incorrect, the answer was ',Astring,'.');
delay(3000);
end;

Until Q=Qlast;



end;
 
You probably get the too many open files error because you frequently open the screen file, but never close it again.

Some other remarks:
- Never, ever reassign the input and/or output file variables unless you're sure about what you're doing!
- Declare two text file variables (dutchwords, englishwords), assign them before you enter the loop, do as many resets as you want on them in the loop, and close them after the loop.
- Declare variables locally if they aren't needed globally.
- Use proper and consequent indentation, it will make your code much more readable.
- To make the program a little more tolerant, you could convert both the correct answer and the answer the user typed in to uppercase and remove preceding and trailing spaces before checking if they're the same.

Regards,
Bert Vingerhoets
vingerhoetsbert@hotmail.com
Don't worry what people think about you. They're too busy wondering what you think about them.
 
... or in other words, every "assign... " has to be matched up with a "close..."; otherwise you leave a dos file slot hanging open, and will soon run out. Of course the close can come very much later. You can leave a file that you use frequently open for the entire run time of your program.

In theory if you don't close the file at the end of the program it will be closed on exit anyway. Personally I think it's good practice to close everything regardless. At least it focusses the mind on what resources you are using.

 
> ... or in other words, every "assign... " has to be matched up with a "close...";

Not necessarily, the assign procedure links a file variable with a file, but the file remains closed. Neither would it be correct to say that for every reset or rewrite there must be a close, because you can reset or rewrite an open file multiple times.
If you have difficulty in tracing open files, you can follow two strategies: (1) place an assign/reset pair at the beginning of the code and a close at the end; or (2) place an assign at the beginning of the code and everywhere you want to access the file, place a reset/close pair with the desired operation in between.
Note that an assign operation is only needed once, unless you want to use the same file variable for multiple files.

Check out faq935-3446 for more information on text files.

Regards,
Bert Vingerhoets
vingerhoetsbert@hotmail.com
Don't worry what people think about you. They're too busy wondering what you think about them.
 
turns out, you were right, i added some additional closes, specifically everytime before i assigned, some how i got the delusion the the 'console' as an input was special. Thanks for the help.

Ant
 
Yup, Bert, you're absolutely right of course. I tend to think of the assign and the close as a pair because it is very rare for me to assign something without opening it, but very common to reset it several times after the assign and before I finally close it.

I have no idea how much extra time a reset requires when the file is not already open compared to a reset merely to move the file-pointer back to the start? Is there a performance cost in all that closing? The closing itself forces a flush from buffer, so I personally would be dubious about closing when I've only written a few characters and have a lot more characters to write.

There is an obvious place where a file gets assigned and not opened, and that's where it turns out not to exist when you do the reset. Such a file cannot be closed since it isn't open!

Antagonist, do you know about {$I-}? You should be aware that reseting a file that doesn't exist creates a runtime error that needs to be dealt with appropriately.
 
There are only 4 possible operations on file variables: open, inout, flush and close. Therefore there is no significant difference in resetting an opened file and resetting a closed file. The real time necessary to open a file depends on the device driver for the file (and even more on the time to get the hardware to work). You can override the device drivers for text files by altering the code pointers in the text file record:
[tt]
TYPE Tbuffer = array[0..127] of char;
driverfunc = function(var f : text) : integer;
text = record
handle : word;
mode : word;
bufsize : word;
reserved : word;
bufpos : word;
bufend : word;
bufptr : ^Tbuffer;
open : driverfunc;
inout : driverfunc;
flush : driverfunc;
close : dirverfunc;
userdata : array[1..16] of byte;
name : array[0..79] of char;
buffer : Tbuffer;
end;[/tt]

When a file doesn't exist, the open function is still called on a reset or rewrite; it's up to the device driver to return a nonzero value as function result.

Regards,
Bert Vingerhoets
vingerhoetsbert@hotmail.com
Don't worry what people think about you. They're too busy wondering what you think about them.
 
But there must be a difference in performance on closing after each small write rather than writing a lot and then closing once. Closing must force any buffers to be written to disk (in the case of a disk file), which takes time. The whole point of having a write buffer is to avoid hunting around the disk every time you want to write a single character...

The reason I suspected there might be a difference between reseting and open and a closed file is that I thought it possible that reseting would require the device driver to check the file exists, if it's not already open (and therefore require time while it pokes around in FATs etc). I assumed the device driver would have a bit of a head start if the file is already open. But of course you're right, it's still got to find the start of the file. And even if it's still open, it may not be fair to assume it hasn't been changed by some other process?

Thanks for info about redirecting etc.
 
As you say, there probably are slight differences in time for each possible operation, but, unless you wrote the driver yourself, you can't make any assumptions on the use of a buffer and on the time to access a physical location on the disk. It is even possible that the operating system schedules disk accesses to optimize performance by making the disk heads move as little as possible. To get a more accurate view of timings, you also have to take into account hardware buffers on the disk controller, various levels of cache memory and multiple memory buffers (provided by the OS, TP, ...).

As you see, the question of time related to I/O operations is not just limited to number and length of instructions.

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