Daanish
Daanish

Reputation: 1091

Read and Write to a file in perl

    this
    is just
    an example.

Lets assume the above is out.txt. I want to read out.txt and write onto the same file.

    <Hi >
    <this>
    <is just>
    <an example.>

Modified out.txt. I want to add tags in the beginning and end of some lines. As I will be reading the file several times I cannot keep writing it onto a different file each time.

EDIT 1 I tried using "+<" but its giving an output like this :

Hi
this
is just
an example.
<Hi >
<this>
<is just>
<an example.>
 **out.txt**

EDIT 2 Code for reference :

open(my $fh, "+<", "out.txt");# or die "cannot open < C:\Users\daanishs\workspace\CCoverage\out.txt: $!";
     while(<$fh>)
     {
        $s1 = "<";
        $s2 = $_;
        $s3 = ">";
        $str = $s1 . $s2 . $s3;
        print $fh "$str";
     }

Upvotes: 1

Views: 14138

Answers (5)

TVNshack
TVNshack

Reputation: 107

Need to specify

use Fcntl qw(SEEK_SET);

in order to use

seek INFILE, 0, SEEK_SET;

Thanks user1703205 for the example.

Upvotes: 0

user1703205
user1703205

Reputation: 126

Read contents in memory and then prepare required string as you write to your file. (SEEK_SET to zero't byte is required.

#!/usr/bin/perl

open(INFILE, "+<in.txt");
@a=<INFILE>;
seek INFILE, 0, SEEK_SET ;
foreach $i(@a)
{ 
    chomp $i;
    print INFILE "<".$i.">"."\n";
}

If you are worried about amount of data being read in memory, you will have to create a temporary result file and finally copy the result file to original file.

Upvotes: 5

vstm
vstm

Reputation: 12537

You could use Tie::File for easy random access to the lines in your file:

use Tie::File;
use strict;
use warnings;

my $filename = "out.txt";
my @array;
tie @array, 'Tie::File', $filename or die "can't tie file \"$filename\": $!";

for my $line (@array) {
  $line = "<$line>";
  # or $line =~ s/^(.*)$/<$1>/g; # -- whatever modifications you need to do
}

untie @array;

Disclaimer: Of course, this option is only viable if the file is not shared with other processes. Otherwise you could use flock to prevent shared access while you modify the file.

Disclaimer-2 (thanks to ikegami): Don't use this solution if you have to edit big files and are concerned about performance. Most of the performance loss is mitigated for small files (less than 2MB, though this is configurable using the memory arg).

Upvotes: 2

ikegami
ikegami

Reputation: 386551

The very idea of what you are trying to do is flawed. The file starts as

H  i  /  t  h  i  s  /  ...

If you were to change it in place, it would look as follows after processing the first line:

<  H  i  >  /  i  s  /  ...

Notice how you clobbered "th"? You need to make a copy of the file, modify the copy, the replace the original with the copy.

The simplest way is to make this copy in memory.

my $file;
{ # Read the file
   open(my $fh, '<', $qfn)
      or die "Can't open \"$qfn\": $!\n";
   local $/;
   $file = <$fh>;
}

# Change the file
$file =~ s/^(.*)\n/<$1>\n/mg;

{ # Save the changes
   open(my $fh, '>', $qfn)
      or die "Can't create \"$qfn\": $!\n";
   print($fh $file);
}

If you wanted to use the disk instead:

rename($qfn, "$qfn.old")
   or die "Can't rename \"$qfn\": $!\n";

open(my $fh_in, '<', "$qfn.old")
      or die "Can't open \"$qfn\": $!\n";
open(my $fh_out, '>', $qfn)
      or die "Can't create \"$qfn\": $!\n";

while (<$fh_in>) {
   chomp;
   $_ = "<$_>";
   print($fh_out "$_\n");
}

unlink("$qfn.old");

Using a trick, the above can be simplified to

local @ARGV = $qfn;
local $^I = '';
while (<>) {
   chomp;
   $_ = "<$_>";
   print(ARGV "$_\n");
}

Or as a one-liner:

perl -i -pe'$_ = "<$_>"' file

Upvotes: 8

Dan
Dan

Reputation: 10786

One option is to open the file twice: Open it once read-only, read the data, close it, process it, open it again read-write (no append), write the data, and close it. This is good practice because it minimizes the time you have the file open, in case someone else needs it.

If you only want to open it once, then you can use the +< file type - just use the seek call between reading and writing to return to the beginning of the file. Otherwise, you finish reading, are at the end of the file, and start writing there, which is why you get the behavior you're seeing.

Upvotes: 1

Related Questions