使用不同的进程在同一文件中进行读写

时间:2010-05-11 10:47:53

标签: perl

我写了两个程序。一个程序将内容同时写入文本文件。另一个程序同时读取该内容。

但是这两个程序应该同时运行。对我来说,程序是正确写入文件。但是另一个程序没有读取文件。

我知道一旦写入过程完成,只有数据将存储在硬盘中。然后另一个进程可以读取数据。

但我希望在单个文件中同时读写不同的进程。我怎样才能做到这一点?

请帮帮我。 以下代码在文件中写入内容

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 个答案:

答案 0 :(得分:4)

您可以使用精心设计的合作协议,如下所示。两端readerwriter都使用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模块工作时为execute-around

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 named pipes似乎与您想要的非常接近,并注意代码的简单性:

<强> 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创建管道,因为它们没有其他同步方法。至少有一个会失败,但只要管道存在,我们就不在乎。

如您所见,所有等待的机器都由系统处理,因此您可以做您关心的事情:阅读和写信息。

答案 1 :(得分:3)

这很有效。

作者:

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);
}

答案 2 :(得分:-1)

你在Windows或* nix上吗?你可能能够在* nix上将这样的东西串在一起,通过使用tail来获取输出,因为它被写入文件。在Windows上,您可以使用FILE_SHARE_READ和/或FILE_SHARE_WRITE调用CreateFile(),以便在您打开文件进行读/写操作时允许其他人访问该文件。您可能需要定期检查文件大小是否已更改,以便知道何时阅读(我不是100%肯定的。)

另一个选项是内存映射文件。