我正在将文件从源位置复制到目标位置,并且文件太大。复制文件时,我想在终端窗口中看到进度条。这是Perl代码的示例片段:
$src_dir = "/home/user/source/";
$dest = "/home/user/destination/";
$file = $src_dir."test_file.csv";
`cp $file $dest`;
print "Copy Done\n";
文件将在几秒钟后复制到此处。但是需要在终端窗口中显示进度条。我们如何实现这一目标?
答案 0 :(得分:1)
以下是如何使用Term::ProgressBar来实现进度条的示例。它使用sysread和syswrite一次写入固定的块大小:
use strict;
use warnings;
use Term::ProgressBar;
use constant BUFSIZE => 8196;
my $fn = 'file.txt';
my $save_fn = 'file2.txt';
my $size = -s $fn;
my $progress = Term::ProgressBar->new ({count => $size, remove => 1});
open ( my $read_fh, '<:raw', $fn ) or die "Could not open file '$fn': $!";
open ( my $write_fh, '>:raw', $save_fn ) or die "Could not open file '$save_fn': $!";
my $buf = "";
my $total_written = 0;
my $next_update = 0;
while (1) {
my $bytes_read = sysread $read_fh, $buf, BUFSIZE;
die "Read error: $!" if !defined $bytes_read;
last if $bytes_read == 0;
my $offset = 0;
my $num_bytes = $bytes_read;
while (1) {
my $bytes_written = syswrite $write_fh, $buf, $num_bytes, $offset;
die "Write error: $!" if !defined $bytes_written;
die "Unexpected" if $bytes_written > $num_bytes;
last if $bytes_written == $num_bytes;
$num_bytes -= $bytes_written;
$offset += $bytes_written;
}
$total_written += $bytes_read;
if ( $total_written > $next_update ) {
$next_update = $progress->update($total_written);
}
}
$progress->update($size);
close $read_fh;
close $write_fh;
答案 1 :(得分:1)
您问了一个令人惊讶的复杂问题。您要运行外部命令(cp
),同时让Perl程序继续执行(产生进度信息)。换句话说,它们都在同一时间执行。
经典方法是在一个单独的进程中执行外部命令,并在等待该进程完成的同时输出更新。
第一部分通常是通过fork
完成该过程来完成的。容易出错,因此我建议使用Proc::Fork。
第二部分需要一些技巧,因为您需要坐在那里等待过程结束,但是需要时不时地输出某些内容,但又不想忙于等待和消耗CPU周期。最安全的方法是在输出之间休眠。为此,我建议使用Time::HiRes(这是标准Perl发行版的一部分)。
还有,这是一些代码:
use strict;
use warnings;
use English; # for more mnemonic special variable names
use POSIX ":sys_wait_h";
use Proc::Fork;
use Time::HiRes qw( usleep );
run_fork {
child {
exec q[sleep 3];
}
parent {
my $child_pid = shift;
my $pid;
my $loop;
STDOUT->autoflush;
while ( 0 == ($pid = waitpid $child_pid, WNOHANG ) ){
print '.';
++$loop;
usleep(5000);
}
print "\n" if $loop;
# for more complete handlng of $CHILD_ERROR, see the
# documentation for the perl system function
die( "error in child process\n" ) if $CHILD_ERROR;
}
};
如果您想查看进度条,请查看Term::ProgressBar