gpt4 book ai didi

perl - 如何使用 File::Map 正确写入文件?

转载 作者:行者123 更新时间:2023-12-04 05:45:17 25 4
gpt4 key购买 nike

我正在使用 File::Map经常将特别小的文本文件映射到内存中,例如处理一些只读的正则表达式。现在我有一个用例,我还需要替换文件中的一些文本,并认为我仍然可以使用 File::Map ,因为它记录了以下内容:

Files are mapped into a variable that can be read just like any other variable, and it can be written to using standard Perl techniques such as regexps and substr.


虽然我有兴趣替换的数据在文件中被正确替换,但我正在丢失数据,因为文件保持其原始大小并且数据最终被截断。新数据比旧数据大一点。这两件事都被警告,如使用以下句子记录的那样:

Writing directly to a memory mapped file is not recommended

Truncating new value to size of the memory map


这两个警告的解释读起来就像不应该使用 File::Map 写任何东西。 ,但它可能适用于人们可以使用截断的文件或根本没有改变整体文件大小的情况。但是第一个引用明确提到支持写入,该规则没有任何异常(exception)。
那么,是否有一些特殊的方法可以安全地使用 File::Map 进行编写? ,例如让基础文件增加等等?第一个警告使用措辞 directly ,我觉得还有其他更好的支持方式来编写吗?
我只是使用 =~ s///目前在映射 View 上,这似乎是错误的方法。我什至找不到任何人尝试使用 File::Map 进行写作。根本上,只有官方测试完全符合我的要求,并期待我收到警告。此外,查看代码,似乎只有一个用例根本不会导致警告,尽管我不明白我是如何触发它的:
static int mmap_write(pTHX_ SV* var, MAGIC* magic) {
struct mmap_info* info = (struct mmap_info*) magic->mg_ptr;
if (!SvOK(var))
mmap_fixup(aTHX_ var, info, NULL, 0);
else if (!SvPOK(var)) {
STRLEN len;
const char* string = SvPV(var, len);
mmap_fixup(aTHX_ var, info, string, len);
}
else if (SvPVX(var) != info->fake_address)
mmap_fixup(aTHX_ var, info, SvPVX(var), SvCUR(var));
else
SvPOK_only_UTF8(var);
return 0;
}
https://metacpan.org/source/LEONT/File-Map-0.55/lib/File/Map.xs#L240
毕竟,如果完全应该避免写作,为什么文档明确提到它是受支持的?如果它至少在所有情况下都导致警告,但对我来说似乎不受支持。

最佳答案

mmap 是文件的一部分到内存的固定大小的映射。

各种映射函数将提供的标量的字符串缓冲区设置为映射的内存页。如果请求,操作系统会将对该缓冲区的任何更改反射(reflect)到文件中,反之亦然。

使用 mmap 的正确方法是修改字符串缓冲区,而不是替换它。

  • 任何改变字符串缓冲区而不改变其大小的东西都是合适的。
    $ perl -e'print "\0"x16' >scratch

    $ perl -MFile::Map=map_file -we'
    map_file my $map, "scratch", "+<";
    $map =~ s/\x00/\xFF/g; # ok
    substr($map, 6, 2, "00"); # ok
    substr($map, 8, 2) = "11"; # ok
    substr($map, 7, 2) =~ s/../22/; # ok
    '

    $ hexdump -C scratch
    00000000 ff ff ff ff ff ff 30 32 32 31 ff ff ff ff ff ff |......0221......|
    00000010
  • 任何替换字符串缓冲区(例如分配给标量)的东西都不行。

    ……有点。该模块注意到您已经替换了标量的缓冲区。它继续将新缓冲区的内容复制到映射内存,然后用指向映射内存的指针替换标量缓冲区。
    $ perl -e'print "\0"x16' >scratch

    $ perl -MFile::Map=map_file -we'
    map_file my $map, "scratch", "+<";
    $map = "4" x 16; # Effectively: substr($map, 0, 16, "4" x 16)
    '
    Writing directly to a memory mapped file is not recommended at -e line 3.

    $ hexdump -C scratch
    00000000 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 |4444444444444444|
    00000010

    除了警告可以使用 no warnings qw( substr ); 静音,[1] 唯一的缺点是这样做需要使用 memcpy复制length($map)字节,同时使用 substr($map, $pos, length($repl), $repl)只需要复制length($repl)字节。
  • 任何改变字符串缓冲区大小的东西都是不行的。
    $ perl -MFile::Map=map_file -we'
    map_file my $map, "scratch", "+<";
    $map = "5" x 32; # Effectively: substr($map, 0, 16, "5" x 16)
    '
    Writing directly to a memory mapped file is not recommended at -e line 3.
    Truncating new value to size of the memory map at -e line 3.

    $ hexdump -C scratch
    00000000 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 |5555555555555555|
    00000010


  • 警告:如果您缩小缓冲区,模块不会发出警告,即使这除了用 NUL 破坏一个字节之外没有任何效果。
    $ perl -e'print "\0"x16' >scratch

    $ perl -MFile::Map=map_file -we'
    map_file my $map, "scratch", "+<";
    substr($map, 0, 16, "6" x 16);
    substr($map, 14, 2, "");
    '

    $ hexdump -C scratch
    00000000 36 36 36 36 36 36 36 36 36 36 36 36 36 36 00 36 |66666666666666.6|
    00000010

    我已经提交了 ticket .

  • 这有点讽刺,因为它或多或少会在不使用 substr 时发出警告。 ,但我想它在使用 substr 时也会发出警告“错误地”。
  • 关于perl - 如何使用 File::Map 正确写入文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53671315/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com