PrimeBeat
PrimeBeat

Reputation: 484

Is there a way to solve an I/O error 6 in Delphi?

procedure TfrmSongs.Display;
var
  i: Integer;
begin
  redOutput.Clear;
  redOutput.Lines.Add('The TOP 10');
  for i := 1 to iCount-1 do
  begin
    redOutput.Lines.Add(IntToStr(i)+arrSongs[i]);
  end;
end;

procedure TfrmSongs.FormActivate(Sender: TObject);
var
  tSongList: TextFile;
  sSong: string;
begin
  iCount := 0;
  AssignFile(tSongList, ExtractFilePath(Application.ExeName)+'Songs.txt');
  Reset(tSongList);
  while not EOF do
  begin
    Readln(tSongList, sSong);
    arrSongs[iCount] := sSong;
    Inc(iCount);
  end;
  CloseFile(tSongList);
  Display;
end;

I'm trying to display the array I tried to create via a text file in a rich edit. But every time I run the app, it gives me an 'I/O error 6' error and nothing displays. I don't know if it's something with the text file or if it's something with the display procedure.

Upvotes: 1

Views: 4487

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598309

There are a few problems with your code, but regarding the I/O error specifically, error 6 means "invalid file handle".

Since you are getting a popup error notification, you clearly have I/O checking enabled, which it is by default.

I/O error 6 is not typical for a failure on System.Reset(), and you are not seeing any other kind of error related to a failure in opening a file, so we can safely assume that the file is being opened successfully, and that System.Readln() and System.CloseFile() are not being passed an invalid I/O handle.

So that leaves just one line that could be receiving an invalid I/O handle:

while not EOF do

System.Eof() has an optional parameter to tell it which file to check. Since you are omitting that parameter, Eof() will use System.Input instead. And a GUI process does not have a STDIN handle assigned by default. So that is likely where error 6 is coming from.

That line needs to be changed to this instead:

while not EOF(tSongFile) do

UPDATE: given the declaration of arrSongs you have shown in comments (arrSongs: array[1..MAX] of string;), there are additional problems with your code. You need to make sure the reading loop does not try to store more than MAX strings in the array. Also, your reading loop is trying to store a string at index 0, which is not a valid index since the array starts at index 1. Also, Display() is skipping the last string in the array. See what happens when you omit important details?

Try this instead:

private
  arrSongs: array[1..MAX] of string;

...

procedure TfrmSongs.Display;
var
  i: Integer;
begin
  redOutput.Clear;
  redOutput.Lines.Add('The TOP 10');
  for i := 1 to iCount do
  begin
    redOutput.Lines.Add(IntToStr(i) + arrSongs[i]);
  end;
end;

procedure TfrmSongs.FormActivate(Sender: TObject);
var
  tSongList: TextFile;
  sSong: string;
begin
  iCount := 0;
  AssignFile(tSongList, ExtractFilePath(Application.ExeName) + 'Songs.txt');
  Reset(tSongList);
  try
    while (not EOF(tSongList)) and (iCount < MAX) do
    begin
      Readln(tSongList, sSong);
      arrSongs[1+iCount] := sSong;
      Inc(iCount);
    end;
  finally
    CloseFile(tSongList);
  end;
  Display;
end;

That being said, I would suggest getting rid of the reading loop completely. You can use a TStringList instead:

uses
  ..., System.Classes;

...

private
  lstSongs: TStringList;

...

procedure TfrmSongs.Display;
var
  i: Integer;
begin
  redOutput.Clear;
  redOutput.Lines.Add('The TOP 10');
  for i := 0 to lstSongs.Count-1 do
  begin
    redOutput.Lines.Add(IntToStr(i+1) + lstSongs[i]);
  end;
end;

procedure TfrmSongs.FormCreate(Sender: TObject);
begin
  lstSongs := TStringList.Create;
end;

procedure TfrmSongs.FormDestroy(Sender: TObject);
begin
  lstSongs.Free;
end;

procedure TfrmSongs.FormActivate(Sender: TObject);
begin
  lstSongs.LoadFromFile(ExtractFilePath(Application.ExeName) + 'Songs.txt');
  Display;
end;

Or, you can use TFile.ReadAllLines() instead:

uses
  ..., System.IOUtils;

...

private
  arrSongs: TStringDynArray;

...

procedure TfrmSongs.Display;
var
  i: Integer;
begin
  redOutput.Clear;
  redOutput.Lines.Add('The TOP 10');
  for i := 0 to High(arrSongs) do
  begin
    redOutput.Lines.Add(IntToStr(i+1) + arrSongs[i]);
  end;
end;

procedure TfrmSongs.FormActivate(Sender: TObject);
begin
  arrSongs := TFile.ReadAllLines(ExtractFilePath(Application.ExeName) + 'Songs.txt');
  Display;
end;

Upvotes: 6

Related Questions