Recent

Author Topic: Write to a new file.  (Read 3053 times)

JimR

  • New Member
  • *
  • Posts: 11
Write to a new file.
« on: June 18, 2019, 06:20:54 am »
I'm running Windows 10, 64 bit, latest version 2.0.2 of Lazarus

I open a file, read it, write to new file, close it. 
No errors.
No new file in the default directory, or anywhere else for that matter.
I'm missing something so basic, but can't see it.

procedure TForm1.Button1Click(Sender: TObject);   
var InFile   : TextFile;
    OutFile  : TextFile;
    Lp1, Lp2 : Integer;
    Str      : String;
begin
AssignFile(InFile,'ResidentData.TXT');
ReSet(InFile);
AssignFile(OutFile,'NewDirectory.TXT');
ReWrite(OutFile);
{$I+}
if IOResult = 0 then Button1.Caption := 'Good';
ReadLn(InFile,Str);
WriteLn(OutFile,Str);
ReadLn(InFile,Str);
WriteLn(OutFile,Str);
for Lp1 := 1 to 207 do  // 207 lines.
  begin
  ReadLn(InFile,Str);
  WriteLn(OutFile,Str);
  end; // lp1.
//Flush(OutFile);
CloseFile(OutFile);
end;

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Write to a new file.
« Reply #1 on: June 18, 2019, 07:46:32 am »
Code: Pascal  [Select][+][-]
  1. program test;
  2. {$ifdef mswindows}{$apptype console}{$endif}
  3. var InFile   : Text;
  4.     OutFile  : Text;
  5.     S        : String;
  6. begin
  7. {$I-}  // should be - for ioresult use, otherwise exceptions. See manual.
  8. Assign(InFile,'residentdata.txt');
  9. Reset(InFile);
  10. if IOResult = 0 then writeln('Infile open');
  11. Assign(OutFile,'newdirectory.txt');
  12. ReWrite(OutFile);
  13. if IOResult = 0 then writeln('outfile created');
  14. while not eof(infile) do
  15. begin
  16.   ReadLn(InFile,S);
  17.   writeln(OutFile,S);
  18. end;
  19. Close(Infile);
  20. Flush(OutFile);
  21. Close(OutFile);
  22. end.
« Last Edit: June 18, 2019, 08:24:16 am by Thaddy »
Specialize a type, not a var.

bytebites

  • Hero Member
  • *****
  • Posts: 633
Re: Write to a new file.
« Reply #2 on: June 18, 2019, 07:56:57 am »
Code: Pascal  [Select][+][-]
  1. for Lp1 := 1 to 207 do  // 207 lines.
or
Code: Pascal  [Select][+][-]
  1. while not eof(infile) do

JangelH

  • Newbie
  • Posts: 1
Re: Write to a new file.
« Reply #3 on: June 18, 2019, 07:59:12 am »
Tested same conditions. Works ok.
¿Did you save your project?

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Write to a new file.
« Reply #4 on: June 18, 2019, 07:59:22 am »
@bytebites Yes that's the same as in my demo.
Specialize a type, not a var.

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Write to a new file.
« Reply #5 on: June 18, 2019, 08:16:39 am »
Shouldn't the {$I+} be {$I-} ?

At least in the code of Thaddy. Because IOResult only works when {$I} is -

In both codes I miss the {$I-}
Always use both {$I-} and {$I+} around the system call and then read out IOResult.

 (Never forget to read out IOResult and only read it once otherwise you'll get into trouble)

Code: Pascal  [Select][+][-]
  1. {$I-}
  2. AssignFile(InFile,'ResidentData.TXT');
  3. ReSet(InFile);
  4. {$I+}
  5. if IOResult <> 0 then
  6. begin
  7.   Button1.Caption := 'Bad opening source file';
  8.   exit;
  9. end;
  10. {$I-}
  11. AssignFile(OutFile,'NewDirectory.TXT');
  12. ReWrite(OutFile);
  13. {$I+}
  14. if IOResult <> 0 then
  15. begin
  16.   Button1.Caption := 'Bad opening destination file';
  17.   exit;
  18. end;
  19. Button1.Caption := 'Good';
« Last Edit: June 18, 2019, 08:23:08 am by rvk »

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Write to a new file.
« Reply #6 on: June 18, 2019, 08:25:03 am »
Shouldn't the {$I+} be {$I-} ?
Yes. I just corrected that. posts crossed.

Note I am not a big fan of assignfile etc. It is assign . Assignfile etc draws in another unit...that is not necessary everything is in system and the other unit simply uses aliases to system.assign etc..
That said: if the mode is objpas that objpas unit is drawn in anyway. but these routines are really annoying.
« Last Edit: June 18, 2019, 08:32:05 am by Thaddy »
Specialize a type, not a var.

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Write to a new file.
« Reply #7 on: June 18, 2019, 08:30:47 am »
Yes, and I would prefer to switch it back on before or after reading out IOResult so that other system calls will fail when encountering an error.

When you leave {$I-} (IOCheck} in the disabled state, the Close or Readln or Writeln might also encounter an error. The program won't catch that in the {$I-} state and just fill in IOResult. In which case the IOResult will trigger somewhere else in your program where the IOCheck is enabled resulting in very strange errors somewhere in your program.

https://www.freepascal.org/docs-html/prog/progsu38.html

If you leave the {$I-} you will also need to read the IOResult after read and write and close to make sure you handle any error from the system-calls.

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Write to a new file.
« Reply #8 on: June 18, 2019, 08:34:59 am »
My approach is different: I usually have either {$I-} and perform all iochecks applicable, or {$I+} with exceptions and object filestreams.
So either lightweight old school all the way (especially for utilities) or use exceptions. But I can see your point.
Note that reading IOResult will destroy it and reset to 0. So I don't see the problem.
See https://www.freepascal.org/docs-html/rtl/system/ioresult.html

Snippet from objpas:
Code: Pascal  [Select][+][-]
  1. Procedure AssignFile(out f:File;p:pchar);
  2. begin
  3.   System.Assign (F,p);
  4. end; //etc
Since these are not inlined there is call overhead.

Note there is one noticable difference: AssignFile has overloads that allows you to set the codepage, which might be of interest to some but not to me, usually.
E.g:
Code: Pascal  [Select][+][-]
  1. Procedure AssignFile(out t:Text;p:pchar; aCodePage : TSystemCodePage);
  2. begin
  3.   System.Assign (T,p);
  4.   SetTextCodePage(T,aCodePage);
  5. end;

« Last Edit: June 18, 2019, 08:46:06 am by Thaddy »
Specialize a type, not a var.

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Write to a new file.
« Reply #9 on: June 18, 2019, 08:44:38 am »
My approach is different: I usually have either {$I-} and perform all iochecks applicable, or {$I+} with exceptions and object filestreams.
So either lightweight old school all the way (especially for utilities) or use exceptions. But I can see your point.
Note that reading IOResult will destroy it and reset to 0. So I don't see the problem.
See https://www.freepascal.org/docs-html/rtl/system/ioresult.html
Yes, that's also a way to go.
But in that case you should also read IOResult after (every) read and write.
Because if you don't you can get a read error (from reading) somewhere else on a perfectly good file because there was still a result from a previous read or write. And that's very hard to debug. So in that case you need to make sure to always handle the IOResult after every system call.

The resetting of IOResult isn't the problem then but the fact an IOResult will not reset with every call. So reset() won't set it to 0 if it is already <> 0 !!!

Thaddy

  • Hero Member
  • *****
  • Posts: 14204
  • Probably until I exterminate Putin.
Re: Write to a new file.
« Reply #10 on: June 18, 2019, 08:48:22 am »
That's what I wrote: you need to check IOresult everywhere, except for assign because that doesn't do IOResult, reset/rewrite do, as do close, flush etc.
That's correct. I wrote a more elaborate example here some years ago. I have added some comments to my previous post, we crossed.
Specialize a type, not a var.

JimR

  • New Member
  • *
  • Posts: 11
Re: Write to a new file.
« Reply #11 on: June 18, 2019, 12:15:17 pm »
Thanks for the input, but the problem is not the {$+} or {$I-}, no error shows up there before or after I made the suggested fixes.  The programs runs without errors, I can even read from the newly created OutFile and display in on the screen.  The problem is when the program ends, the OutFile is not saved to the disk.  Sorry, I was probably not clear in my definition of my problem. 

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Write to a new file.
« Reply #12 on: June 18, 2019, 12:21:18 pm »
... or after I made the suggested fixes.
Please provide the code you have now (after the fixes) because your original code (with the {$I+} is plain wrong because IOResult doesn't work in the + state).

(Could you also put the code inside [code] [/code] tags, you can use the # above the editor. Thanks)

JimR

  • New Member
  • *
  • Posts: 11
Re: Write to a new file.
« Reply #13 on: June 18, 2019, 12:56:55 pm »
procedure TForm1.Button1Click(Sender: TObject);
var InFile   : TextFile;
    OutFile  : TextFile;
    Lp1, Lp2 : Integer;
    Str      : String;
    Ch       : Char;
begin
AssignFile(InFile,'ResidentData.TXT');
ReSet(InFile);
{$I+}
if IOResult <> 0 then
  begin
  Label1.Caption := 'bad input file';
  exit;
  end;
{$I-}
AssignFile(OutFile,'NewDirectory.TXT');
ReWrite(OutFile);
{$I+}
if IOResult <> 0 then
  begin
  Label2.Caption := 'bad output file';
  exit;
  end;
{$I-}
for Lp1 := 1 to 207 do  // 207 lines.
  begin
  ReadLn(InFile,Str);
  WriteLn(OutFile,Str);
  Label3.Caption := IntToStr(Lp1);
  end; // lp1.
Flush(OutFile);
Reset(OutFile);
ReadLn(OutFile,Str);
Label4.Caption := Str;
CloseFile(OutFile);
end;

Label2.caption and Label3.caption are both unwritten to, so no problems there.
Label3.caption is 207, so all 207 lines were read and written.
Label4.caption has the first line copied from source file, so that worked.
I can take out the ioresult lines of code with no change to anything.
The problem is after the procedure complete, and I look in the directory where there should be a new file called 'NewDirectory.TXT', there isn't one.

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: Write to a new file.
« Reply #14 on: June 18, 2019, 01:03:32 pm »
First off, you didn't put you code between [code] [/code] tags !!

Second... What is that Reset() on line 33 doing??
You didn't yet close the output file so you shouldn't read from it.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var InFile   : TextFile;
  3.     OutFile  : TextFile;
  4.     Lp1, Lp2 : Integer;
  5.     Str      : String;
  6.     Ch       : Char;
  7. begin
  8. AssignFile(InFile,'ResidentData.TXT');
  9. ReSet(InFile);
  10. {$I+}
  11. if IOResult <> 0 then
  12.   begin
  13.   Label1.Caption := 'bad input file';
  14.   exit;
  15.   end;
  16. {$I-}
  17. AssignFile(OutFile,'NewDirectory.TXT');
  18. ReWrite(OutFile);
  19. {$I+}
  20. if IOResult <> 0 then
  21.   begin
  22.   Label2.Caption := 'bad output file';
  23.   exit;
  24.   end;
  25. {$I-}
  26. for Lp1 := 1 to 207 do  // 207 lines.
  27.   begin
  28.   ReadLn(InFile,Str);
  29.   WriteLn(OutFile,Str);
  30.   Label3.Caption := IntToStr(Lp1);
  31.   end; // lp1.
  32. Flush(OutFile);
  33. Reset(OutFile); //???????????????
  34. ReadLn(OutFile,Str);
  35. Label4.Caption := Str;
  36. CloseFile(OutFile);
  37. end;
  38.  

And you didn't do a while loop for the 127 lines (which you should).
And you also don't close the infile.
And you have mismatching {$I-} and {$I+}
Every {$I-} should have a {$I+} and everything between will effect IOResult.
Your code is just inverted the {$I-} and {$I+} and leaves it at - for the read loop (which you should do the other way around).

Try this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   InFile: TextFile;
  4.   OutFile: TextFile;
  5.   Str: string;
  6. begin
  7.   AssignFile(InFile, 'ResidentData.TXT');
  8.   {$I-} ReSet(InFile); {$I+}
  9.   if IOResult <> 0 then
  10.   begin
  11.     Label1.Caption := 'bad input file';
  12.     exit;
  13.   end;
  14.   AssignFile(OutFile, 'NewDirectory.TXT');
  15.   {$I-} ReWrite(OutFile); {$I+}
  16.   if IOResult <> 0 then
  17.   begin
  18.     Label2.Caption := 'bad output file';
  19.     CloseFile(InFile); // don't forget to close the infile
  20.     exit;
  21.   end;
  22.   while not EOF(InFile) do
  23.   begin
  24.     ReadLn(InFile, Str);
  25.     WriteLn(OutFile, Str);
  26.     Label3.Caption := 'no need for line count';
  27.   end;
  28.   CloseFile(OutFile);
  29.   CloseFile(InFile); // don't forget to close the infile
  30. end;
« Last Edit: June 18, 2019, 01:12:48 pm by rvk »

 

TinyPortal © 2005-2018