Solved

Delete a Line from a File

Posted on 2004-08-25
11
261 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
[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
  • 4
  • 2
  • 2
  • +3
11 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11891534
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
ID: 11891587
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
ID: 11891594
Too late, Magik :P
0
Independent Software Vendors: 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!

 

Author Comment

by:fabyola
ID: 11892269
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
ID: 11892285
Or it doesn´t matter how big the file is ?
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11892861
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
ID: 11892940
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
ID: 11893728
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
ID: 11893764
Sorry, LRHGuy. Didn't read all the comments before posting mine.
0
 
LVL 6

Expert Comment

by:bpana
ID: 11894141
>> 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
ID: 11894764
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

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!

Question has a verified solution.

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

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…
How to Install VMware Tools in Red Hat Enterprise Linux 6.4 (RHEL 6.4) Step-by-Step Tutorial

730 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