#perl
#perl
Вопрос:
Содержимое файла:
456 name1 name2 345 678
423 name3 name4 345 678
435 name5 name6 345 678
866 name7 name8 345 678
Содержимое файла после вставки строки :
456 name1 name2 345 678
423 name3 name4 345 678
Name3_Found
435 name5 name6 345 678
866 name7 name8 345 678
Содержимое файла, которое я получаю:
456 name1 name2 345 678
423 name3 name4 345 678
Name3_Found
me6 345 678
866 name7 name8 345 678
код:
open (temp2, " <$file") or die "Could not open file";
my $point;
while(my $lin =<temp2>) {
$point = tell(temp2);
if ( $lin =~ /name5/ ){
seek(temp2,$point-2,0);
chk:
while (my $lin =<temp2>){
my @rw = split" ",$lin;
if ($rw[1] eq "name3" ) {
say temp2 "Name3_Found";
} elsif( $lin =~ /name5/){
last chk;
}
}
}
}
close temp2;
Кто-нибудь знает, почему он удаляет другие данные строки? и как это исправить?
Комментарии:
1. Ну, вы перезаписываете существующие байты (
435 name5 na
) с добавлением (Name3_Foundn
). Файл представляет собой последовательность байтов, и между ними нельзя «добавить» или что-то подобное. Вам нужно скопировать ее и добавить эту новую строку туда, где она находится в процессе.2. @zdim, я не копировал.
Ответ №1:
Здесь вы смешиваете несколько вещей. При записи в дескриптор файла в смешанном режиме ( <
) данные не вставляются. Вы перезаписываете то, что уже есть.
Если у вас есть записи фиксированной длины и вы хотите перейти к определенной записи, используйте seek
. Чтобы заменить запись, вы должны записать точно такое же количество октетов. Если вы записываете слишком мало октетов, вы оставляете позади октеты из предыдущей записи, а если вы записываете слишком много, вы перезаписываете следующую запись.
Если вы хотите делать вещи, ориентированные на строки, не используйте смешанный режим open
. Откройте файл, чтобы прочитать его, и выведите в новый файл. perlfaq5 описывает это в разделе «Как мне изменить, удалить или вставить строку в файл или добавить в начало файла?».
Я думаю, что в 4-м издании Learning Perl все еще была глава об этом материале.
Ответ №2:
Только потому, что вы спросили: «… и как это исправить?»
#!/usr/bin/env perl
use Data::Dumper;
use Hash::Util qw(lock_keys);
use strict;
use warnings;
my $file=q{TheData.txt};
# using three argument open and dying with error
open (my $temp, " <",$file)
or die "Could not open '$file'! $!";
my %ptr_h=(READER=>tell $temp,WRITER=>tell $temp);
# The only keys we're going to use are READER and WRITER --- anything will error out
lock_keys(%ptr_h);
# Our buffer
my @buffer_a;
while(my $line=<$temp>) {
# The next read will start here
$ptr_h{READER}=tell($temp);
# Make any changes to the line - pushing them onto the buffer
if ($line =~ m{name3}) { # only if name3
# pushing them onto the buffer
push @buffer_a,$line.qq{Name3_Foundn};
}
else { # otherwise just save it!
push @buffer_a,$line;
}
# end of changes
# Do we have anything to write and the room to write it
while (@buffer_a amp;amp; length($buffer_a[0]) <= $ptr_h{READER}-$ptr_h{WRITER}) {
# We do have room to write the first record of the buffer
seek $temp,$ptr_h{WRITER},0;
# Enough room to write $Buffer_a[0] so write it ...
print $temp shift(@buffer_a);
$ptr_h{WRITER}=tell($temp);
};
}
# Go back to where we were reading
continue {
seek $temp,$ptr_h{READER},0;
};
# We've read and processed all of the file
# ... now write out what remains of the buffer
seek $temp,$ptr_h{WRITER},0;
while (@buffer_a) {
print $temp shift(@buffer_a);
};
# ... and truncate the file
truncate $temp,tell($temp);
# ... and close
close($temp)
or die "Can't close '$file'! $!";
ACHTUNG: если что-то должно произойти во время вашего обновления, вы можете оказаться «в ручье без весла».