Solved

Normal read/write "routine"

Posted on 2001-07-11
9
162 Views
Last Modified: 2010-04-06
What is the standard "routine" for reading a file, modifying it, and saving it to disk again?

Currently, my simple app reads in a text file line by line.  For each line, it simply does a writeln to a temporary output file.  When the program sees the line that needs to be changed, it writes the correct line to the temp file instead.  All the other lines in the file are then read and written to and from the original and temp files, respectively.  When this is complete, both files are closed, the original is deleted, and the temp one gets the old file's name.

The problem is that the new file loses the old file's attributes, such as its creation date and possibly its permissions.  What is the best way to make a change to a file, WITHOUT reading it all into one string, modifying the string, and writing the string back to the original?
0
Comment
Question by:Pummel
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
9 Comments
 
LVL 1

Accepted Solution

by:
bnemmers earned 44 total points
ID: 6273300
The reason that the new file loses the attributes is
because you have created a new file and not just used the
old one.

Why don't you use TStringList.LoadFromFile(FileName)
load the complete file then search through the StringList
for the string that needs to be changed then call
TStringList.SaveToFile(FileName)

The Modified date will changed along with the last access date but the created date should remain the same.

If this doesn't work for you then try FileSetAttr function.

Bill.
0
 

Author Comment

by:Pummel
ID: 6273873
That sounds like a good idea.  But what do you do when the file is really, really big and the change you need to add text in the middle of the file.  Is there a memory-efficient way to do that?  This is kind of the focus of my question, but I can see that I didn't say it.
0
 
LVL 3

Expert Comment

by:VSF
ID: 6273973
Check this homepage for some ideas on read and write using strings:
http://delphi.does.it/

If u have a big file u should think about some patch technics:
Maybe this sample can give you some ideas:

PATCH FILES
procedure TForm1.Button1Click(Sender: TObject);
var
 f: file;
 l: longint;
 datei, altstring, neustring, s: string;
begin
  altstring := 'Windows 95';
  neustring := 'BadWindows';
  datei := 'C:\kopie von io.sys';

  s := altstring;
  assignFile(f, datei);
  reset(f,1);
  for l := 0 to filesize(f)-length(altstring)-1 do
  begin
   Application.ProcessMessages;
   seek(f,l);
   blockread(f,altstring[1],length(altstring));
   if altstring = s then
   begin
    seek(f,l);
    blockwrite(f,neustring[1],length(neustring));
    label1.caption := 'Status: String found and patched!';
   end;
   Application.ProcessMessages;
  end;
  closeFile(f);
end;


This samples opens a file seeks for a given string and then modyfies the string if found!

VSF
www.victory.hpg.com.br
UIN:14016999
www.enge.cjb.net
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Expert Comment

by:bnemmers
ID: 6274244
Hi,

You didn?t say how big is big 1000kb, 10,000kb etc..
You might want to look at TFileStream.
You could breakup the file into lets say
3 pieces and use Seek(SomeOffset) for your starting position.

Is the file organized is some fashion?
If so you could use this read large chunks of data.
Could you post an example of the file or send me copy?
Are the changes always in the middle of the file?

Bill ;)
billnemmers@csi.com
0
 
LVL 3

Expert Comment

by:Sabre
ID: 6275567
Just a thought, but if it is the created date, last modified date, permissions etc that you want to maintain - why not read them first then reset them back when you have changed the file.
0
 
LVL 3

Expert Comment

by:rondi
ID: 6279756
This is a straightforward problem.

1. Just read the file however you like
   If you're worried about efficiency then either use
   VSF's BlockRead suggestion (only if the strings are
   of fixed & equal length) or use TFileStream (best)
   This way you've got direct file read/write access.

2. Use FileSetAttr to change the file's attributes if you
   really don't want anyone to know about your little
   patch operation ;)

If you wanna do line-by-line processing then using TFileStream may be a bit tricky, unless you write a
TFileStream descendant whose read/write methods only handle
lines.
You could ofcourse use the TextFile readln and writeln routines. From experience, TextFile's readln routine doesn't work properly with blank lines and you'll probably
need to increase the buffer size.

Just read up on all this in the help file and you should
be OK.

rondi.
0
 

Author Comment

by:Pummel
ID: 6286560
bnemmers comments were the most helpful.  I didn't include a file size because the file I'm working with is really small.  But I was just curious what I would do if my project involved a large file.  So it was kind of a what-if scenario.

Rondi and Sabre seemed to sum up what bnemmers said and rondi was right about the restrictions imposed by the patch techniques.  Maybe in the future I'll be a good enough programmer to confidently write a descendant class from TFileStream.

Thank you everyone for your time in helping me understand this concept more.
0
 
LVL 1

Expert Comment

by:bnemmers
ID: 6286848
Hi,

One last thing

This is the simplest way to load and locate the string.
You might want to place each operation in a new thread.

procedure TForm1.FormCreate(Sender: TObject);
begin
  fStringList := TStringList.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  fStringList.Free;
end;

procedure TForm1.btnLoadClick(Sender: TObject);
begin
  if dlgOpen.Execute then
  begin
    fFileName := dlgOpen.FileName;
    //The file size was 124mb and it took 128 sec to open on a pentIII w/128mb
    fStringList.LoadFromFile(fFileName);  
  end;
end;

procedure TForm1.btnSearchClick(Sender: TObject);
begin
  //The bad string was located in the middle of the file
  //and it took 27 sec to find the string
  fIndex := fStringList.IndexOf(StringToSearchFor);
  if Index > 0 then
  begin
    fTheCorrectString := fStringList.Strings[Index];
  end;
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  if ((fStringList.Count > 0) and (fFileName <> '')) then
  begin
    fStringList.Strings[fIndex] := fTheCorrectString; //Edit string first
    //Took 191 sec to save back to disk.
    fStringList.SaveToFile(fFileName);
  end;
end;
0
 

Author Comment

by:Pummel
ID: 6287226
Why thank you.

About that SaveToFile command--Does the creation date really stay the same, along with the permissions, like you said in your first comment?
0

Featured Post

[Webinar] Code, Load, and Grow

Managing multiple websites, servers, applications, and security on a daily basis? Join us for a webinar on May 25th to learn how to simplify administration and management of virtual hosts for IT admins, create a secure environment, and deploy code more effectively and frequently.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Mobile Keyboard covers the display of the TMemo 3 114
Delphi inherited method 6 88
Delphi Yen format 3 72
Multi-layered image in FireMonkey 9 93
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…
Are you ready to implement Active Directory best practices without reading 300+ pages? You're in luck. In this webinar hosted by Skyport Systems, you gain insight into Microsoft's latest comprehensive guide, with tips on the best and easiest way…

734 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question