Pummel
asked on
Normal read/write "routine"
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?
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?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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(altstri ng)-1 do
begin
Application.ProcessMessage s;
seek(f,l);
blockread(f,altstring[1],l ength(alts tring));
if altstring = s then
begin
seek(f,l);
blockwrite(f,neustring[1], length(neu string));
label1.caption := 'Status: String found and patched!';
end;
Application.ProcessMessage s;
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
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
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(altstri
begin
Application.ProcessMessage
seek(f,l);
blockread(f,altstring[1],l
if altstring = s then
begin
seek(f,l);
blockwrite(f,neustring[1],
label1.caption := 'Status: String found and patched!';
end;
Application.ProcessMessage
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
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
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
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.
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.
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.
ASKER
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.
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.
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(f FileName);
end;
end;
procedure TForm1.btnSearchClick(Send er: 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(String ToSearchFo r);
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(fFi leName);
end;
end;
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:
begin
fStringList.Free;
end;
procedure TForm1.btnLoadClick(Sender
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(f
end;
end;
procedure TForm1.btnSearchClick(Send
begin
//The bad string was located in the middle of the file
//and it took 27 sec to find the string
fIndex := fStringList.IndexOf(String
if Index > 0 then
begin
fTheCorrectString := fStringList.Strings[Index]
end;
end;
procedure TForm1.btnSaveClick(Sender
begin
if ((fStringList.Count > 0) and (fFileName <> '')) then
begin
fStringList.Strings[fIndex
//Took 191 sec to save back to disk.
fStringList.SaveToFile(fFi
end;
end;
ASKER
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?
About that SaveToFile command--Does the creation date really stay the same, along with the permissions, like you said in your first comment?
ASKER