Каков наилучший способ вырезать файл в строку в Perl?

Да, Там больше, чем один способ сделать это, но должен быть канонический или наиболее эффективный или наиболее сжатый способ. Я добавлю ответы, которые я знаю, и посмотрю, что перколит к вершине.

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

Ответ 1

Как насчет этого:

use File::Slurp;
my $text = read_file($filename);

ETA: note Ошибка # 83126 для File-Slurp: дыра безопасности с кодировкой (UTF-8). Я рекомендую использовать File::Slurper (отказ от ответственности: я написал его), также потому, что он имеет лучшие значения по умолчанию для кодировок:

use File::Slurper 'read_text';
my $text = read_text($filename);

или Path::Tiny:

use Path::Tiny;
path($filename)->slurp_utf8;

Ответ 2

Мне нравится делать это с блоком do, в котором я локализую @ARGV, поэтому я могу использовать алмазный оператор для создания магии файлов для меня.

 my $contents = do { local(@ARGV, $/) = $file; <> };

Если вам нужно, чтобы это было немного более надежным, вы можете легко превратить это в подпрограмму.

Если вам нужно что-то действительно надежное, которое обрабатывает всевозможные специальные случаи, используйте File:: Slurp. Даже если вы не собираетесь использовать его, посмотрите на источник, чтобы увидеть все сумасшедшие ситуации, с которыми он должен справиться. Файл:: Slurp имеет большую проблему безопасности, которая не имеет решения. Частью этого является его неспособность правильно обрабатывать кодировки. Даже мой быстрый ответ имеет эту проблему. Если вам нужно обработать кодировку (возможно, потому, что вы не делаете все UTF-8 по умолчанию), это расширяется до:

my $contents = do {
    open my $fh, '<:encoding(UTF-8)', $file or die '...';
    local $/;
    <$fh>;
    };

Если вам не нужно менять файл, вы можете использовать File::Map.

Ответ 3

При написании File::Slurp (что является лучшим способом), Ури Гутман много исследовал множество способов разграбления и которые является наиболее эффективным. Он записал его результаты здесь и включил их в файл File:: Slurp.

Ответ 4

open(my $f, '<', $filename) or die "OPENING $filename: $!\n";
$string = do { local($/); <$f> };
close($f);

Ответ 5

О чем подумать (особенно по сравнению с другими решениями):

  • Лексические дескрипторы файлов
  • Уменьшить область действия
  • Уменьшить магию

Итак, я получаю:

my $contents = do {
  local $/;
  open my $fh, $filename or die "Can't open $filename: $!";
  <$fh>
};

Я не большой поклонник магии < > за исключением случаев, когда на самом деле используется magic < > . Вместо того, чтобы притворяться, почему бы просто не использовать открытый вызов напрямую? Это не намного больше работает, и явственно. (True magic < > , особенно при обработке "-", гораздо лучше работать, чтобы отлично подражать, но мы все равно не используем его здесь.)

Ответ 6

mmap (сопоставление памяти) строк может быть полезно, если вы:

  • Имейте очень большие строки, которые вы не хотите загружать в память
  • Требуется слепо быстро инициализация (вы получаете постепенный ввод-вывод при доступе)
  • Имейте случайный или ленивый доступ к строке.
  • Может потребоваться обновить строку, но она только расширяет ее или заменяет символы:
#!/usr/bin/perl
use warnings; use strict;

use IO::File;
use Sys::Mmap;

sub sip {

    my $file_name = shift;
    my $fh;

    open ($fh, '+<', $file_name)
        or die "Unable to open $file_name: $!";

    my $str;

    mmap($str, 0, PROT_READ|PROT_WRITE, MAP_SHARED, $fh)
      or die "mmap failed: $!";

    return $str;
}

my $str = sip('/tmp/words');

print substr($str, 100,20);

Обновление: май 2012

Следующее довольно хорошо эквивалентно, после замены Sys:: Mmap с Файл:: Карта

#!/usr/bin/perl
use warnings; use strict;

use File::Map qw{map_file};

map_file(my $str => '/tmp/words', '+<');

print substr($str, 100, 20);

Ответ 7

use Path::Class;
file('/some/path')->slurp;

Ответ 8

{
  open F, $filename or die "Can't read $filename: $!";
  local $/;  # enable slurp mode, locally.
  $file = <F>;
  close F;
}

Ответ 9

use IO::All;

# read into a string (scalar context)
$contents = io($filename)->slurp;

# read all lines an array (array context)
@lines = io($filename)->slurp;

Ответ 10

См. сводку Perl6::Slurp, которая невероятно гибкая и в целом делает правильные вещи с минимальными усилиями.

Ответ 11

Это не быстрый, ни независимый от платформы, а действительно злой, но он короткий (и я видел это в коде Ларри Уолла;):

 my $contents = `cat $file`;

Дети, не делайте это дома; -).

Ответ 13

Никто ничего не сказал о чтении или sysread, так что это простой и быстрый способ:

my $string;
{
    open my $fh, '<', $file or die "Can't open $file: $!";
    read $fh, $string, -s $file;   # or sysread
    close $fh;
}

Ответ 14

Для однострочных вы обычно можете использовать переключатель -0 (с помощью -n), чтобы perl сразу прочитал весь файл (если файл не содержит нулевых байтов):

perl -n0e 'print "content is in $_\n"' filename

Если это двоичный файл, вы можете использовать -0777:

perl -n0777e 'print length' filename

Ответ 15

Кандидат на худший способ сделать это! (См. Комментарий.)

open(F, $filename) or die "OPENING $filename: $!\n";
@lines = <F>;
close(F);
$string = join('', @lines);

Ответ 16

Отрегулируйте специальную переменную разделителя записи $/

undef $/;
open FH, '<', $filename or die "$!\n";
my $contents = <FH>;
close FH;

Ответ 17

# Takes the name of a file and returns its entire contents as a string.
sub getfile 
{
  my($filename) = @_;
  my($result);

  open(F, $filename) or die "OPENING $filename: $!\n";
  while(<F>) { $result .= $_; }
  close(F);

  return $result;
}