Каков наилучший способ записать файл в строку в Perl? - PullRequest
46 голосов
/ 16 октября 2008

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

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

Ответы [ 17 ]

70 голосов
/ 16 октября 2008

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

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

ETA: примечание Ошибка # 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;
44 голосов
/ 16 октября 2008

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

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

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

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

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

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

35 голосов
/ 18 октября 2008

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

20 голосов
/ 16 октября 2008
open(my $f, '<', $filename) or die "OPENING $filename: $!\n";
$string = do { local($/); <$f> };
close($f);
11 голосов
/ 16 октября 2008

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

  1. Лексические файловые ручки
  2. Уменьшить область действия
  3. Уменьшить магию

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

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

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

10 голосов
/ 16 октября 2008

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 на File :: Map

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

use File::Map qw{map_file};

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

print substr($str, 100, 20);
8 голосов
/ 08 декабря 2008
use Path::Class;
file('/some/path')->slurp;
7 голосов
/ 16 октября 2008
{
  open F, $filename or die "Can't read $filename: $!";
  local $/;  # enable slurp mode, locally.
  $file = <F>;
  close F;
}
5 голосов
/ 11 августа 2011
use IO::All;

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

# read all lines an array (array context)
@lines = io($filename)->slurp;
4 голосов
/ 16 октября 2008

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

 my $contents = `cat $file`;

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...