DanDaemon
asked on
Need make Seek function for text file...
Hello guys,
I have a problem with Seek with Textfile files...
I have text XML file:
<?xml version="1.0" encoding= "UTF-8"?>'
<history version="1.3">
</history>
I need to add node before </history> but using standard I/O functions... Then I need to assign file handle to this file, open it for read/write, seek to end of file. But I have </history> there.... I need to write string like <item>...</item> before tag </history>...
Is it possible to do without using XML parser?
Thanks!
I have a problem with Seek with Textfile files...
I have text XML file:
<?xml version="1.0" encoding= "UTF-8"?>'
<history version="1.3">
</history>
I need to add node before </history> but using standard I/O functions... Then I need to assign file handle to this file, open it for read/write, seek to end of file. But I have </history> there.... I need to write string like <item>...</item> before tag </history>...
Is it possible to do without using XML parser?
Thanks!
2 GB ? Maybe you better use DataBase insted of XML ?
ASKER
I can't use database. I need write XML file.
I just wrote this for you, let me know if it does what you want
can't "insert" the data, but can make a 2nd file from teh first (then replace original)
has to go through the whole 2gig i'm afraid, but i can't think of a faster way
Easy enough to add a progress bar to it
can't "insert" the data, but can make a 2nd file from teh first (then replace original)
has to go through the whole 2gig i'm afraid, but i can't think of a faster way
Easy enough to add a progress bar to it
procedure TForm1.Button1Click(Sender: TObject);
begin
InsertXMLTagHeader('file.xml', 'history', 'item', #13#10'<note>this was changed to include item tag</note>'#13#10, 1024, 1024);
end;
procedure TForm1.InsertXMLTagHeader(Filename, InsertAroundThisTag, TagName, ExtraDataInsideTag: string; ExpectToFindOpenTag, ExpectToFindEndTag: longint);
const
MaxBufferLen = 1; //6384;
var
FSin, FSOut: TFileStream;
b: byte;
s: string;
opentagtype1, opentagtype2, closetag: string;
success: boolean;
foundstartat, foundendat, cnt: longint;
buffer: array[0..MaxBufferLen-1] of byte;
amounttoread: longint;
begin
opentagtype1 := '<' + uppercase(InsertAroundThisTag) + '>';
opentagtype2 := '<' + uppercase(InsertAroundThisTag) + ' ';
closetag := '</' + uppercase(InsertAroundThisTag) + '>';
success := false;
s := '';
cnt := 0;
foundstartat := -1;
foundendat := -1;
FSin := TFileStream.Create(filename, fmOpenRead OR fmShareDenyNone);
FSOut := TFileStream.Create(filename + '.tmp', fmCreate OR fmShareExclusive);
try
repeat
inc(cnt);
FSin.Read(b, sizeof(b));
if (foundstartat > -1) then
begin // we already have a partial match, keep going
s := s + chr(b);
if ( (uppercase(s) = opentagtype1) or (uppercase(s) = opentagtype2) ) then
begin
success := true; // we have found the entire tag start
end
else if ( (pos(uppercase(s), opentagtype1) = 1) or (pos(uppercase(s), opentagtype1) = 1) ) then
begin
// we have found another character in the sequence, keep going
end
else
begin // broken the partial match, write what we have so far, and start again
foundstartat := -1; //
FSOut.Write(s[1], length(s));
s := '';
end;
end
else if (uppercase(chr(b)) = opentagtype1[1]) then
begin // found the start of a match, save it and keep looking
s := chr(b);
foundstartat := FSIn.Position-1;
end
else
FSOut.Write(b, sizeof(b));
until (success or (cnt > ExpectToFindOpenTag));
if success then
begin // now find the end
success := false;
cnt := 0;
repeat
inc(cnt);
FSIn.Seek(0-cnt, soFromEnd);
FSin.Read(b, sizeof(b));
if (foundendat > -1) then
begin // we already have a partial match, keep going
s := chr(b) + s;
if (uppercase(s) = closetag) then
begin
success := true; // we have found the entire tag end
end
else if (pos(uppercase(s), closetag) <> 0) then
begin
// we have found another character in the sequence, keep going
end
else
begin // broken the partial match, start again
foundendat := -1; //
s := '';
end;
end
else if (uppercase(chr(b)) = closetag[length(closetag)]) then
begin // found the start (end actually) of a match, save it and keep looking
s := chr(b);
foundendat := FSIn.Position-1;
end
until (success or (cnt > ExpectToFindEndTag));
if success then
begin // now insert our new data, then read until the end tag, insert our end tag then the rest of the file
s := '<' + TagName + '>' + ExtraDataInsideTag;
FSOut.Write(S[1], length(S));
FSIn.Seek(foundstartat, soFromBeginning);
repeat
amounttoread := MaxBufferLen;
if ( (FSIn.Position + MaxBufferLen) > foundendat) then
amounttoread := foundendat - FSIn.Position;
FSIn.Read(buffer, amounttoread);
FSOut.Write(buffer, amounttoread);
until FSIn.Position >= foundendat;
s := '</' + TagName + '>';
FSOut.Write(S[1], length(S));
repeat
amounttoread := MaxBufferLen;
if ( (FSIn.Position + MaxBufferLen + 1) >= FSIn.Size) then
amounttoread := FSIn.Size - FSIn.Position - 1;
FSIn.Read(buffer, amounttoread);
FSOut.Write(buffer, amounttoread);
until (FSIn.Position + 1) = FSIn.Size;
end;
end
else
Raise Exception.Create(Format('did not find "%s" within %d bytes', [InsertAroundThisTag, ExpectToFindOpenTag]));
finally
FSin.Free;
FSOut.Free;
end;
if FileExists(filename + '.tmp') then
begin
// RenameFile(filename, filename + '.old');
// RenameFile(filename + '.tmp', filename);
// DeleteFile(filename + '.old');
end
end;
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Thanks! This is what I need!
ASKER