为什么这会破坏我的yaml文件?

时间:2012-09-05 14:01:38

标签: perl yaml

当我运行下面的脚本时,我得到一个像这样的损坏的yaml文件

--- 
1: 
  name1: abc
  name2: abc
---
me3: abc
---

问题

有人能看出我做错了吗?

#!/usr/bin/perl

use strict;
use YAML::Syck;
use Fcntl ':flock', 'SEEK_SET';
use warnings;
use Data::Dumper;

my $acc;
my $acc_fh;

$acc->{1}{name1} = "abc";

unlink 'test.yaml';

# write initial
open F, '>', 'test.yaml';
print F YAML::Syck::Dump($acc);
close F;


($acc, $acc_fh) = read_yaml_with_lock('test.yaml');
$acc->{1}{name2} = "abc";
$acc->{1}{name3} = "abc";
write_yaml_with_lock($acc, $acc_fh);

($acc, $acc_fh) = read_yaml_with_lock('test.yaml');
delete $acc->{1}{name3};
write_yaml_with_lock($acc, $acc_fh);


sub read_yaml_with_lock {
    my ($file) = @_;

    open my $fh, '+<', $file or die $!;
    flock($fh, LOCK_EX) or die $!;

    my $obj = YAML::Syck::LoadFile($fh); # this dies on failure
    return ($obj, $fh);
}

sub write_yaml_with_lock {
    my ($obj, $fh) = @_;

    my $yaml = YAML::Syck::Dump($obj);
    $YAML::Syck::ImplicitUnicode = 1;
    seek $fh, 0, SEEK_SET;   # seek back to the beginning of file

    print $fh $yaml . "---\n";
    close $fh;
}

2 个答案:

答案 0 :(得分:3)

您两次写入同一文件。在第二次,您编写的YAML代码比第一次短,因为您在调用之间删除了该哈希密钥。但是,您第一次没有unlink文件,第二次写入文件后也没有truncate。{所以你看到的腐败是第一次写的文件的一部分,但第二次没有被覆盖。

答案 1 :(得分:3)

"me3"部分是" name3"的剩余部分,被"---\n"部分覆盖(4个字符)。当您第一次写时,您有更多数据。然后你回退文件句柄位置并写一个较短的数据,这不会覆盖所有旧数据。

我认为你的解决方案“应该”是跳过这个传递文件句柄并重绕它,而是为每个子例程使用适当的open。 E.g:

sub read_yaml {
    my $file = shift;
    open my $fh, '<', $file or die $!;
    ...
    close $fh;
}

sub write_yaml {
    my ($file, $obj) = @_;
    open my $fh, '>', $file or die $!;
    ...
    close $fh;
}

在操作之间保持文件句柄打开并不是那么有用或有效,并且它带来了一些困难。