0

Can anybody please explain me why I am hitting 'I/O error 998' in the below block read?

function ReadBiggerFile: string;
var
  biggerfile: file of char;
  BufArray: array [1 .. 4096] of char; // we will read 4 KB at a time
  nrcit, i: integer;
  sir, path: string;
begin
  path := ExtractFilePath(application.exename);
  assignfile(biggerfile, path + 'asd.txt');
  reset(biggerfile);
  repeat
    blockread(biggerfile, BufArray, SizeOf(BufArray), nrcit);
    for i := 1 to nrcit do
    begin
      sir := sir + BufArray[i];
      Form4.Memo1.Lines.Add(sir);
    end;
  until (nrcit = 0);
  closefile(biggerfile);
  ReadBiggerFile := sir;
end;
Dalija Prasnikar
  • 27,212
  • 44
  • 82
  • 159
jimsweb
  • 1,082
  • 2
  • 17
  • 37
  • 1
    I mis-read the code when I answered ... it was incorrect, so I deleted it. I'm unsure what is causing the error. Sorry about that. – Mark Wilkins Feb 29 '12 at 04:31
  • NP. thanks for your helping hand. – jimsweb Feb 29 '12 at 04:38
  • 1
    Why you not just use Form4.Memo1.Lines.LoadFromfile() or [TStringList.LoadFromfile](http://docwiki.embarcadero.com/Libraries/XE2/en/System.Classes.TStrings.LoadFromFile)? Anyway try declaring the biggerfile as `file` instead of file of char and replace reset(biggerfile) for `reset(biggerfile,1)` – RRUZ Feb 29 '12 at 04:39
  • :) Actually the memo is not part of the original coding. I just wanted to make sure that the block read works perfectly, and this is the reason I am trying to load it into memo. – jimsweb Feb 29 '12 at 04:42
  • 1
    Even if the memo is not part of the code you can use the `TStringList.LoadFromFile()` method or try using the suggestions of my above comment. – RRUZ Feb 29 '12 at 04:44
  • @ BRUZ. reset(biggerfile,1) , this is the place where i made the mistake. Thanks a lot! – jimsweb Feb 29 '12 at 04:52
  • 2
    @jimsweb: The message text of `I/O error 998` is **Invalid access to memory location** (c.f. Windows.pas). Btw, You can elaborate, post an answer to your own question (after all it's been resolved) and accept it. – menjaraz Feb 29 '12 at 05:39
  • 2
    This is the most diabolical way to load a file. Building strings character by character. A better question would be to ask how to load a file and then we could give you one line answers that perform well. – David Heffernan Feb 29 '12 at 07:26
  • 1
    Since my fix fixed your issue, you're clearly not using Delphi7. I removed the tag and replaced it with something more appropriate. – Cosmin Prund Feb 29 '12 at 08:23

2 Answers2

5

I think you miss-tagged the question and you're using Delphi 2009+, not Delphi 7. I got the error in the title bar trying your exact code on Delphi 2010 (unicode Delphi). When you say:

var biggerfile: file of Char;

You're declaring the biggerfile to be a file of "records", where each record is a Char. On Unicode Delphi that's 2 bytes. You later request to read SizeOf(BufArray) records, not bytes. That is, you request to 4096 x 2 = 8192 records. But your buffer is only 4096 records long, so you get a weird error.

I was able to fix your code by simply replacing Char with AnsiChar, since AnsiChar has a size of 1, hence the SizeOf() equals Length().

The permanent fix should involve moving from the very old Pascal-style file operations to something modern, TStream based. I'm not sure exactly what you're trying to obtain, but if you simply want to get the content of the file in a string, may I suggest something like this:

function ReadBiggerFile: AnsiString;
var
  biggerfile: TFileStream;
begin
  biggerfile := TFileStream.Create('C:\Users\Cosmin Prund\Downloads\AppWaveInstall201_385.exe', fmOpenRead or fmShareDenyWrite);
  try
    SetLength(Result, biggerfile.Size);
    biggerfile.Read(Result[1], biggerfile.Size);
  finally biggerfile.Free;
  end;
end;
Cosmin Prund
  • 25,498
  • 2
  • 60
  • 104
  • Thank you. It fixed the issue. But, it seems my code cant read the content of the text file. It is showing something like this. (chinese) '獡൤樊浩൳愊摳਍楪獭 – jimsweb Feb 29 '12 at 07:30
  • Why I wanted to go with block read is because, my text file is having huge data. I have read somewhere that stream read is slow compared to block read, though i cannot confirm the authenticity. – jimsweb Feb 29 '12 at 07:34
  • I have tried out your code. It works perfectly. Thank you. However, I have 30 lakh rows in my text file. I am trying to load it into a TMemo. Is it possible to reduce the load time? – jimsweb Feb 29 '12 at 07:51
  • 1
    Only unbuffered stream reads can be slow. Look at `TReader` and `TWriter`. Also, @DavidHeffernan posted a great implementation of a buffered file stream in this answer: http://stackoverflow.com/a/5639712/62391 – jpfollenius Feb 29 '12 at 07:53
  • 1
    The way I wrote that `Read` command, it reads the whole file *at once*. You can't possibly beat that with buffering! You're seeing weird characters because there's a miss-match between the character format on disk and the character format in your application. Internally your application uses WideChar as the format, but you're very unlikely to find a UTF16 encoded file. You've most likely got a ANSI encoded file (or UTF8 encoded file), and you're interpreting every two bytes from the file as one char. – Cosmin Prund Feb 29 '12 at 08:10
  • 1
    About optimization: Allot can be said about "premature optimization". You need correct code and you need to optimize it later, as late as possible. And you need to profile your code to make sure you're optimizing the actual trouble code. If one reads text from a file and puts it in a `TMemo`, the *slow* bit is going to be *putting text in the memo*, not reading from disk. – Cosmin Prund Feb 29 '12 at 08:15
  • 1
    Another optimization flow in your original code: You're reading the file 4kb at a time, but then you're building the `sir` one character at a time, appending one char each time. When you do that, the string needs to be re-allocated, a memory block one `char` larger is allocated, the original is copied over, then your new `char` is copied. That's *awfully* slow, especially if you're talking about large files. If you need help optimizing a method ask for optimization tips: This question was about getting rid of the `998` error, I ignored everything else, thinking it's just demo code. – Cosmin Prund Feb 29 '12 at 08:18
3

Hi: I had the same issue and i simply passed it the first element of the buffer which is the starting point for the memory block like so:

    AssignFile(BinFile,binFileName);
    reset(BinFile,sizeof(Double));
    Aux:=length(numberArray);
    blockread(BinFile,numberArray[0],Aux, numRead);
    closefile(BinFile);