Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 268
  • Last Modified:

Delete a Line from a File

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
fabyola
Asked:
fabyola
  • 4
  • 2
  • 2
  • +3
1 Solution
 
Wim ten BrinkCommented:
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
 
Magic55Commented:
create a TStringList and load the file with the funtion LoadFromFile.
Delete the lines and use SaveToFile
/ TK
0
 
Wim ten BrinkCommented:
Too late, Magik :P
0
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
fabyolaAuthor Commented:
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
 
fabyolaAuthor Commented:
Or it doesn´t matter how big the file is ?
0
 
Wim ten BrinkCommented:
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
 
LRHGuyCommented:
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
 
Pierre CorneliusCommented:
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
 
Pierre CorneliusCommented:
Sorry, LRHGuy. Didn't read all the comments before posting mine.
0
 
bpanaCommented:
>> 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
 
Wim ten BrinkCommented:
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

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 4
  • 2
  • 2
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now