pascal skips file whilst it is not empty

拈花ヽ惹草 提交于 2019-12-14 04:09:47

问题


I am trying to read some data from a txt file using pascal. When I use a while loop to keep doing actions whilst the file has not ended pascal ignores the while loop and proceeds to the end of my program. Don't really know why this is happening the file I am using is a .txt file which is most certainly not empty!

Code beneath

program Wiki_Lezen;

{$mode objfpc}

 TYPE wikiNew=RECORD
  naam,omschrijving:string;
 END;

  var f: file of wikiNew;
  var bestandsNaam:string;
  var wiki:wikiNew;
  var teller:integer;



begin

  writeln('Geef een bestandsnaam op');
  readln(bestandsNaam);
  ASSIGN(f,bestandsNaam);
  RESET(f);

  while not EOF(f) do
  begin
     read(f,wiki);
     writeln('wikinaam: ', wiki.naam);
     writeln('Geef een omschrijving voor wiki');
     readln(wiki.omschrijving);
     write(f,wiki);
  end;

  CLOSE(f);

  writeln;
  writeln('Om het programma te stoppen druk op <ENTER>');
  readln();
end.  

回答1:


A wikinew record is 512 bytes (two shortstrings with 255 chars + each 1 length byte).

Is your file a series of records of 512 bytes with two shortstrings inside? Or are you trying to read a general textfile? That won't work. "file of" is for constant size data only.

The file type you are looking for is text, or if that isn't allowed, file of char is needed.




回答2:


Update I have updated my example code and the rest of this answer to use ShortStrings as suggested by a comment by Marco van de Voort, for which I am obliged. With my updated code, which both creates and reads the data file, I cannot reproduce your problem. The code writes 3 wiki records to the file and successfully reads them back.

program ReadTextFileTestShortString;

{$mode objfpc}  //{$H+}

uses
  SysUtils;

 type wikiNew = record
  naam,omschrijving:string;
 end;

  var f : file of wikiNew;
  var bestandsNaam:string;
  var wiki:wikiNew;
  var teller:integer;
begin
  // First construct a data file name, based on the executable's name
  bestandsNaam := ExtractFilePath(ParamStr(0)) + ' Wiki.Dat';

  //  Next, generate the file
  Assign(f, bestandsNaam);
  Rewrite(f);
  for teller := 1 to 3 do begin
    wiki.naam := 'Name' + IntToStr(teller);
    wiki.omschrijving := 'Omschrijving' + IntToStr(teller);
    write(f, wiki);
  end;

  //  Now, read the file
  Reset(f);
  while not Eof(f) do begin
    read(f, wiki);
    writeln('Name: ', wiki.naam);
    writeln('Description: ', wiki.omschrijving);
  end;
  Close(f);
  readln;

end.

I will have to leave it to you to investigate why you apparently get different behaviour with your code. Perhaps the "user" is not entering a file name which includes an absolute path and so is reading a different version of the file than the one you assume.

Btw, the previous version of this answer was based on the assumption that you were using so-called "huge" strings and received a down-vote. which was reasonable enough, but I would hope the down-vote could now be removed.

I do not understand how you are getting your code to compile. As @Tom Brunberg noted in a comment, a string in FPC is a reference type, and you cannot declare a file of a reference type. When I attempt to compile your code, I get

ReadFileTest.pas(12,26) Error: Typed files cannot contain reference-counted types.

In the case of string, the reason FPC does not allow a file of a record containing a string is pretty obvious: A string can contain any arbitrary sequence of characters up to 2Gb in length, so when reading the file, the RTL would have no means of knowing where one string field ends and the next field or record begins. Historically, Pascal files of record have always beeb based on records which are of a fixed length, known at compile time, so that the process of writing an instance of the record to the file involves simply writing an image of the record in memory into the file.

So, if you want to store a record containing string fields, the most straightforward way to do it is to use a text file and store the record's individual fields as separate lines in it, e.g. as follows:

Code:

uses
  SysUtils;

 type wikiNew = record
  naam,omschrijving:string;
 end;

  var f : Text;  // declares a text file
  var bestandsNaam:string;
  var wiki:wikiNew;
  var teller:integer;
begin
  //  First construct a data file name, based on the executable's name
  //  This is to avoid the user having to type the file name correctly
  //  and to ensure that the file name includes an absolute path

  bestandsNaam := ExtractFilePath(ParamStr(0)) + ' Wiki.Dat';


  //  Next, generate the file
  Assign(f, bestandsNaam);
  Rewrite(f);
  for teller := 1 to 3 do begin
    wiki.naam := 'Name' + IntToStr(teller);
    wiki.omschrijving := 'Omschrijving' + IntToStr(teller);
    writeln(f, wiki.naam);
    writeln(f, wiki.omschrijving);
  end;

  //  Now, read the file
  Reset(f);
  while not Eof(f) do begin
    readln(f, wiki.naam);
    readln(f, wiki.omschrijving);
    writeln('Name: ', wiki.naam);
    writeln('Description: ', wiki.omschrijving);
  end;
  Close(f);
  readln;

end.

So, don't attempt to mix 'n match Pascal file of [record] files and Text files. file of [record] files, when properly used, do work fine, but need to be based on records of fixed length, which your file of wikiNew necessarily is not, because the record definition includes string fields.

Btw, there was a comment to the effect that a "priming read" might be necessary. It isn't, and should never be necessary with correctly written Pascal code.



来源:https://stackoverflow.com/questions/48097196/pascal-skips-file-whilst-it-is-not-empty

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!