Чтение и запись в одном файле с другим процессом - PullRequest
5 голосов
/ 11 мая 2010

Я написал две программы. Одной программой является одновременная запись содержимого в текстовый файл. Другая программа читает этот контент одновременно.

Но обе программы должны запускаться одновременно. Для меня программа написать файл правильно. Но другая программа не читает файл.

Я знаю, что как только процесс записи будет завершен, на жестком диске будут храниться только данные. Затем другой процесс может прочитать данные.

Но я хочу одновременно читать и писать с разными процессами в одном файле. Как я могу это сделать?

Пожалуйста, помогите мне. Следующий код записывает содержимое в файл

sub generate_random_string
{
    my $length_of_randomstring=shift;# the length of 
       # the random string to generate

    my @chars=('a'..'z','A'..'Z','0'..'9','_');
    my $random_string;
    foreach (1..$length_of_randomstring)
    {
        # rand @chars will generate a random 
        # number between 0 and scalar @chars
        $random_string.=$chars[rand @chars];
    }
    return $random_string;
}
#Generate the random string
open (FH,">>file.txt")or die "Can't Open";
while(1)
{
my $random_string=&generate_random_string(20);
sleep(1);
#print $random_string."\n";
print FH $random_string."\n";
}

Следующий код читает содержимое. Это еще один процесс

 open (FH,"<file.txt") or die "Can't Open";
              print "Open the file Successfully\n\n";
              while(<FH>)
              {
                  print "$_\n";
              }

Ответы [ 3 ]

4 голосов
/ 11 мая 2010

Вы можете использовать сложный протокол сотрудничества, такой как в следующем. Оба конца, reader и writer, используют общий код в модуле TakeTurns, который обрабатывает суетливые детали, такие как блокировка и место, где находится файл блокировки. Клиентам нужно только указать, что они хотят делать, когда у них есть эксклюзивный доступ к файлу.

Читатель

#! /usr/bin/perl

use warnings;
use strict;

use TakeTurns;

my $runs = 0;
reader "file.txt" =>
       sub {
         my($fh) = @_;
         my @lines = <$fh>;
         print map "got: $_", @lines;
         ++$runs <= 10;
       };

автор

#! /usr/bin/perl

use warnings;
use strict;

use TakeTurns;

my $n = 10;
my @chars = ('a'..'z','A'..'Z','0'..'9','_');

writer "file.txt" =>
       sub { my($fh) = @_;
             print $fh join("" => map $chars[rand @chars], 1..$n), "\n"
               or warn "$0: print: $!";
           };

Модуль TakeTurns выполняет на работе:

package TakeTurns;                               

use warnings;                                    
use strict;                                      

use Exporter 'import';                           
use Fcntl qw/ :DEFAULT :flock /;                 

our @EXPORT = qw/ reader writer /;               
my $LOCKFILE = "/tmp/taketurns.lock";            

sub _loop ($&) {
  my($path,$action) = @_;
  while (1) {
    sysopen my $lock, $LOCKFILE, O_RDWR|O_CREAT
                                   or die "sysopen: $!";
    flock $lock, LOCK_EX           or die "flock: $!";
    my $continue = $action->();
    close $lock                    or die "close: $!";
    return unless $continue;
    sleep 0;
  }
}

sub writer {
  my($path,$w) = @_;
  _loop $path =>
        sub {
          open my $fh, ">", $path   or die "open $path: $!";
          my $continue = $w->($fh);
          close $fh                 or die "close $path: $!";
          $continue;
        };
}

sub reader {
  my($path,$r) = @_;
  _loop $path =>
        sub {
          open my $fh, "<", $path        or die "open $path: $!";
          my $continue = $r->($fh);
          close $fh                      or die "close $path: $!";
          $continue;
        };
}

1;

Пример вывода:

got: 1Upem0iSfY
got: qAALqegWS5
got: 88RayL3XZw
got: NRB7POLdu6
got: IfqC8XeWN6
got: mgeA6sNEpY
got: 2TeiF5sDqy
got: S2ksYEkXsJ
got: zToPYkGPJ5
got: 6VXu6ut1Tq
got: ex0wYvp9Y8

Даже несмотря на то, что у вас было так много проблем, все еще есть проблемы. Протокол ненадежен, поэтому reader не может гарантировать просмотр всех сообщений, отправляемых writer. Если writer не активен, reader может читать одно и то же сообщение снова и снова.

Вы можете добавить все это, но более разумным подходом будет использование абстракций, которые уже предоставляет операционная система.

Например, Unix именованные каналы кажутся довольно близкими к тому, что вы хотите, и обратите внимание, насколько простой код:

pread

#! /usr/bin/perl

use warnings;
use strict;

my $pipe = "/tmp/mypipe";
system "mknod $pipe p 2>/dev/null";

open my $fh, "<", $pipe or die "$0: open $pipe: $!";

while (<$fh>) {
  print "got: $_";
  sleep 0;
}

pwrite

#! /usr/bin/perl

use warnings;
use strict;

my $pipe = "/tmp/mypipe";
system "mknod $pipe p 2>/dev/null";

open my $fh, ">", $pipe or die "$0: open $pipe: $!";

my $n = 10;
my @chars = ('a'..'z','A'..'Z','0'..'9','_');

while (1) {
  print $fh join("" => map $chars[rand @chars], 1..$n), "\n"
    or warn "$0: print: $!";
}

Оба конца пытаются создать канал, используя mknod, потому что у них нет другого метода синхронизации. По крайней мере, один из них выйдет из строя, но нам все равно, пока существует труба.

Как видите, все механизмы ожидания обрабатываются системой, поэтому вы делаете то, что вам нужно: чтение и запись сообщений.

3 голосов
/ 11 мая 2010

Это работает.

Писатель:

use IO::File ();

sub generate_random_string {...}; # same as above

my $file_name = 'file.txt';
my $handle = IO::File->new($file_name, 'a');
die "Could not append to $file_name: $!" unless $handle;
$handle->autoflush(1);

while (1) {
    $handle->say(generate_random_string(20));
}

Читатель:

use IO::File qw();

my $file_name = 'file.txt';
my $handle = IO::File->new($file_name, 'r');
die "Could not read $file_name: $!" unless $handle;

STDOUT->autoflush(1);
while (defined (my $line = $handle->getline)) {
    STDOUT->print($line);
}
0 голосов
/ 11 мая 2010

вы на windows или * nix? вы могли бы связать что-то подобное в * nix, используя tail, чтобы получить выходные данные, как они записаны в файл. В окнах вы можете вызывать CreateFile () с FILE_SHARE_READ и / или FILE_SHARE_WRITE, чтобы позволить другим получить доступ к файлу, пока он открыт для чтения / записи. Вам, возможно, придется периодически проверять, изменился ли размер файла, чтобы узнать, когда читать (я не уверен на 100%).

другой вариант - это отображенный в память файл.

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