Solved

Delete a Line from a File

Posted on 2004-08-25
11
252 Views
Last Modified: 2010-08-05
I have a file with alot of lines in it. For example: File.txt

60M200407014708990506058       0022D03533203534
60A200407014708990506058       CANC000000007890
60A200407014708990506058       I   000000021980
60A200407014708990506058       1800000000020850
60A200407014708990403225       CANC000000035836

I want to open this file "File.txt" and delete for example the first 2 lines of the file and the last one. then it woul stay for example:

60A200407014708990506058       I   000000021980
60A200407014708990506058       1800000000020850

with no blank spaces on the line deleted.
0
Comment
Question by:fabyola
  • 4
  • 2
  • 2
  • +3
11 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
Comment Utility
You won't like the answer, I fear, but the easiest way is by using a stringlist...

var List:TStringList;
begin
  List := TStringList.Create;
  List.LoadFromFile('File.txt');
  // Delete last-to-first or else the index numbers get mised up.
  // Keep in mind, lists are 0-based...
  List.Delete(List.Count-1);
  List.Delete(1);
  List.Delete(0);
  List.SaveToFile('File.txt');
  List.Free;
end;

Other solutions that won't require you to read the whole file are a lot harder since you will actually have to move data around in the file. This means opening the file, finding the exact locations of the lines you want to remove and overwriting them with the data a bit further on... It would be possible to do and it would perform a bit faster, especially for huge files, but unfortunately it's not a simple solution...
0
 
LVL 4

Expert Comment

by:Magic55
Comment Utility
create a TStringList and load the file with the funtion LoadFromFile.
Delete the lines and use SaveToFile
/ TK
0
 
LVL 17

Expert Comment

by:Wim ten Brink
Comment Utility
Too late, Magik :P
0
 

Author Comment

by:fabyola
Comment Utility
I need a way to do it withou loading it into a StringList because the file is Too big. I need a way to open the file and edit it.
0
 

Author Comment

by:fabyola
Comment Utility
Or it doesn´t matter how big the file is ?
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 17

Expert Comment

by:Wim ten Brink
Comment Utility
Doing it without loading the whole thing in memory is a bit more complicated. There's just no easy solution for this. One way to do this is like this:

var
  FileIn, FileOut: TextFile;
  Line: string;
  LineCount: Integer;
begin
  AssignFile(FileIn, 'File.txt');
  Reset(FileIn);
  AssignFile(FileIn, 'File.new.txt');
  Rewrite(FileOut);
  LineCount := 0;
  while not EOF(FileIn) do begin
    Inc(LineCount);
    ReadLn(FileIn, Line);
    if (LineCount <> 1) and (LineCount <> 2) and (LineCount <> 3009) then WriteLn(FileOut, Line);
  end;
  CloseFile(FileIn);
  CloseFile(FileOut);
end;

The drawback is of course that you now have two large files. You'll have to delete one and rename the other afterwards...

There's also an option by using only one file variable. Either as a file of byte or just as a plain file. (of nothing) But then you have to determine in your code where lines end and move data to the beginning, overwriting the parts that you want to be removed. Finally you'd have to truncate the file to it's new length. This is quite a bit complex code, though...
0
 
LVL 7

Expert Comment

by:LRHGuy
Comment Utility
I did something similar...it's a copy procedure that takes a "filter" to select which lines to keep. It will work for any size file, as long as you have the disk space...

type
  tFilterFunc=function(aLine:string):boolean;

procedure CopyFileAndFilter(aFN_FROM,aFN_TO:string; aFilter:tFilterFunc);
var
  F,C:textfile;
  Line:String;
begin
  {$I-}
  assignfile(F,aFN_FROM);   {Get file}
  reset(F);
  assignfile(C,aFN_TO);
  rewrite(C);
  while not eof(F) do begin
    readln(F,Line);
    if aFilter(Line) then
      writeln(C,Line);
  end;
  closefile(C);
  closefile(F);
end;

function Filt(aLine:string):boolean; far;
begin
  Result:=pos('A',aline)=0;  //any kind of test you want, return RESULT=TRUE to keep the line.
end;

procedure DoItNow;
begin
  CopyFileAndFilter('Unit2.Pas','Unit2.txt',Filt);
 / / probably should erase the original file and rename new one here.
end;
0
 
LVL 14

Expert Comment

by:Pierre Cornelius
Comment Utility
Procedure DeleteFirst2AndLastLineOfFile(FileName: string);
var OrigFile,NewFile: File;
    s: string;
begin
  AssignFile(NewFile, FileName);
  AssignFile(OrigFile, ChangeFileExt(FileName, '.old'));

  Reset(OrigFile);
  Rewrite(NewFile);

  //skip 1st two lines
  readln(OrigFiles);
  readln(OrigFiles);

  While Not Eof(OrigFile) do
  begin
    readln(OrigFile,s);
    if Not Eof(OrigFile) then writeln(NewFile,s); //only write it if not the last line
  end;
 
  CloseFile(OrigFile);
  CloseFile(NewFile);
  DeleteFile(ChangeFileExt(FileName, '.old')); //if you wish
end;

Kind regards
Pierre
0
 
LVL 14

Expert Comment

by:Pierre Cornelius
Comment Utility
Sorry, LRHGuy. Didn't read all the comments before posting mine.
0
 
LVL 6

Expert Comment

by:bpana
Comment Utility
>> I need a way to do it withou loading it into a StringList because the file is Too big. I need a way to open the file and edit it.
didn't quite understood how you want to edit it.

if manually then:

use a TMemo component. to load the file into the memo:
Memo1.Lines.LoadFromFile('YourFileName');

to save this back to the file:
Memo1.Lines.SaveToFile('YourFileName');
0
 
LVL 17

Accepted Solution

by:
Wim ten Brink earned 50 total points
Comment Utility
Okay, a single-file method (that might ruin your textfile if it's not a proper textfile!)

procedure RemoveLine( Filename: string );
type
  TLine = record
    Start: Int64;
    Length: Int64;
    Delete: Boolean;
  end;
  TLines = array of TLine;
var
  AFile: file of Char;
  Lines: TLines;
  I, J: Integer;
  C: Char;
  CurPos: Int64;
begin
  SetLength( Lines, 0 );
  AssignFile( AFile, Filename );
  Reset( AFile );
  while not EOF( AFile ) do begin
    // We have a new line.
    I := Length( Lines );
    SetLength( Lines, I + 1 );
    // Set the start positions.
    Lines[ I ].Start := FilePos( AFile );
    // By default, delete none...
    Lines[ I ].Delete := False;
    // Find the end of the line.
    repeat
      Read( AFile, C );
    until EOF( AFile ) or ( C in [ #10, #13 ] );
    // Read the next character. #13 and #10 are generally in pairs.
    if not EOF( AFile ) then Read( AFile, C );
    Lines[ I ].Length := FilePos( AFile ) - Lines[ I ].Start;
  end;
  // Okay, deleting lines 1, 2, 101 and the last one... Don't forget the list is 0-based so subtract 1...
  Lines[ 0 ].Delete := True;
  Lines[ 1 ].Delete := True;
  Lines[ 100 ].Delete := True;
  Lines[ High( Lines ) ].Delete := True;
  // Now we're going to move all the bytes backwards... Rewind file.
  Seek( AFile, 0 );
  // Walk through the lines.
  for I := Low( Lines ) to High( Lines ) do begin
    // Move it if it isn't deleted.
    if not Lines[ I ].Delete then begin
      CurPos := FilePos( AFile );
      // But only move lines if they are further away in the file!
      if ( CurPos < Lines[ I ].Start ) then begin
        for J := 0 to Pred( Lines[ I ].Length ) do begin
          // Go to the character to copy.
          Seek( AFile, Lines[ I ].Start + J );
          Read( AFile, C );
          // Go to the position where the copy needs to be written.
          Seek( AFile, CurPos );
          Write( AFile, C );
          Inc( CurPos );
        end;
      end
      else begin
        Seek( AFile, Lines[ I ].Start + Lines[ I ].Length );
      end;
    end;
  end;
  // Cut off the rest of the file!
  Truncate( AFile );
  CloseFile( AFile );
end;

Well, you have to modify this code a bit to suit your own needs but it shows you how to remove lines without the need to read the whole file in memory. It could be made faster too by using blockreads and stuff like that but I'm just showing the principle here, not the optimized code.
I do several steps in this routine. First I determine where all the lines are located in the file. This information can then be used to select all the lines that I want to be removed. (The first two, one somewhere in-between and the one on the end.) Finally, I start moving the text in the file to the new positions. Once everything is processed, the file is truncated and task is done.

It could be a lot better optimized, though. And it could be done even without keeping a list of lines, but that would be a pretty complicated task. Besides, the list is useful if you want to delete lines counted from the end...

Keep in mind that this routine wants textfiles that end with a CR/LF on every line. And it will assume that if it finds one of them, the next one will be the other of this pair.
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
This video discusses moving either the default database or any database to a new volume.
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

771 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now