Perl: запись файла в N-й позиции - PullRequest
5 голосов
/ 08 сентября 2010

Я пытаюсь записать в файл в N-й позиции.Я попытался с приведенным ниже примером, но он пишет в конце.Пожалуйста, помогите достичь этого.

#!/usr/bin/perl

open(FILE,"+>>try.txt")
or
die ("Cant open file try.txt");

$POS=5;

   seek(FILE,$POS,0);

   print FILE "CP1";

Ответы [ 5 ]

4 голосов
/ 08 сентября 2010

Если я правильно вас понимаю, если содержимое файла

123456789

Вы хотите изменить это на

1234CP157689

Этого нельзя добиться, используя режимы, поставляемые для open (независимо от языка программирования).

Вам нужно открыть исходный файл и другой временный файл (см. File :: Temp . Считайте до точки вставки из источника и запишите содержимое во временный файл, напишите, что вы хотите вставьте, затем запишите оставшуюся часть исходного файла во временный файл, закройте источник и rename временный к источнику.

Если вы собираетесь сделать это с помощью seek, оба файла должны быть открыты в двоичном режиме.

Вот пример использования строчного ввода и текстового режима:

#!/usr/bin/perl

use strict; use warnings;
use File::Temp qw( :POSIX );

my $source = 'test.test';
my $temp = tmpnam;

open my $source_h, '<', $source
    or die "Failed to open '$source': $!";

open my $temp_h, '>', $temp
    or die "Failed to open '$temp' for writing: $!";

while ( my $line = <$source_h> ) {
    if ( $line =~ /^[0-9]+$/ ) {
        $line = substr($line, 0, 5) . "CP1" . substr($line, 5);
    }
    print $temp_h $line;
}

close $temp_h
    or die "Failed to close '$temp': $!";

close $source_h
    or die "Failed to close '$source': $!";

rename $temp => $source
    or die "Failed to rename '$temp' to '$source': $!";
3 голосов
/ 08 сентября 2010

Вы открываете файл в режиме чтения-записи.Попробуйте открыть файл в режиме чтения-записи:

my $file = "try.txt";
open my $fh, "+<", $file
    or die "could not open $file: $!";

Также обратите внимание на использование трех аргументов open, лексического дескриптора файла и $!.

#!/usr/bin/perl

use strict;
use warnings;

#create an in-memory file
my $fakefile = "1234567890\n";
open my $fh, "+<", \$fakefile
    or die "Cant open file: $!";

my $offset = 5;

seek $fh, $offset, 0
    or die "could not seek: $!";

print $fh "CP1";

print $fakefile;

Код, напечатанный выше:

12345CP190
2 голосов
/ 08 сентября 2010

«Вставка» строки в функцию может (в основном) выполняться на месте.См. Слегка используемую truncate встроенную функцию.

open my $fh, '+<', $file or die $!;
seek $fh, 5, 0;
$/ = undef;
$x = <$fh>;   # read everything after the 5th byte into $x
truncate $fh, 5;
print $fh "CPI";
print $fh $x;
close $fh;
2 голосов
/ 08 сентября 2010

это работает для меня

use strict;
use warnings;

open( my $fh, '+<', 'foo.txt' ) or die $!;

seek( $fh, 3, 0 );

print $fh "WH00t?";

это также более "современное" использование open (), см. http://perldoc.perl.org/functions/open.html

Файл будет закрыт, когда $ fh выйдет из области видимости.

0 голосов
/ 09 сентября 2010

Если ваш файл ориентирован на строки или записи, вы можете легко вставить строки или изменить отдельные строки с помощью основного модуля Tie :: File Это позволит обрабатывать файл как массив и строку Perl иманипулирование массивом для изменения файла в памяти.С помощью этого метода вы можете безопасно работать с большими файлами, превышающими объем вашей оперативной памяти.

Вот пример:

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

#create the default .txt file:
open (my $out, '>', "nums.txt") or die $!;
while(<DATA>) { print $out "$_"; }
close $out or die $!;

tie my @data, 'Tie::File', "nums.txt" or die $!;

my $offset=5;
my $insert="INSERTED";

#insert in a string: 
$data[0]=substr($data[0],0,$offset).$insert.substr($data[0],$offset) 
    if (length($data[0])>$offset);

#insert a new array element that becomes a new file line:       
splice @data,$offset,0,join(':',split(//,$insert));

#insert vertically: 
$data[$_]=substr($data[$_],0,$offset) .
          substr(lc $insert,$_,1) .
          substr($data[$_],$offset) for (0..length($insert));

untie @data; #close the file too...

__DATA__
123456789
234567891
345678912
456789123
567891234
678912345
789123456
891234567
912345678

Вывод:

12345iINSERTED6789
23456n7891
34567s8912
45678e9123
56789r1234
I:N:St:E:R:T:E:D
67891e2345
78912d3456
891234567
912345678

Изменения файлов сTie::File сделаны на месте и как массив модифицируется.Вы можете использовать Tie::File только в первой строке вашего файла для изменения и вставки по вашему запросу.Вы можете поместить sleep между модами массива и использовать tail -n +0 -f для файла и наблюдать за изменением файла, если хотите ...

В качестве альтернативы, если ваш файл имеет разумный размер и вы хотите обращаться с ним каксимволов, вы можете прочитать весь файл в память, выполнить строковые операции с данными, а затем записать измененные данные обратно.Обратите внимание:

use strict; use warnings;

#creat the default .txt file:
open (my $out, '>', "nums.txt") or die $!;
while(<DATA>) { print $out "$_"; }
close $out or die $!;

my $data;
open (my $in, '<', "nums.txt") or die $!;
{ local $/=undef; $data=<$in>; }
close $in or die $!;

my $offset=5;
my $insert="INSERTED";

open (my $out, '>', "nums.txt") or die $!;
print $out substr($data,0,$offset).$insert.substr($data,$offset);
close $out or die $!;

__DATA__
123456789
2
3
4
5
6
7
8
9

Вывод:

12345INSERTED6789
2
3
4
5
6
7
8
9

Если вы рассматриваете файлы как символы, имейте в виду, что в Windows файлы в текстовом режиме имеют \r\n для новой строки.Это два символа, если они открыты в двоичном режиме.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...