Qual é a melhor maneira de abrir e ler um arquivo em Perl?

Por favor, note – Eu não estou olhando para o caminho “certo” para abrir / ler um arquivo, ou a maneira que eu deveria abrir / ler um arquivo a cada momento. Estou interessado apenas em descobrir que maneira a maioria das pessoas usa e talvez aprenda alguns methods novos ao mesmo tempo:) *

Um bloco de código muito comum em meus programas Perl é abrir um arquivo e ler ou gravar nele. Eu tenho visto muitas maneiras de fazer isso, e meu estilo de realizar essa tarefa mudou ao longo dos anos algumas vezes. Eu só estou querendo saber qual é o melhor método (se existe uma maneira melhor) de fazer isso?

Eu costumava abrir um arquivo como este:

my $input_file = "/path/to/my/file"; open INPUT_FILE, "<$input_file" || die "Can't open $input_file: $!\n"; 

Mas acho que tem problemas com o trapping de erros.

Adicionar um parêntese parece corrigir o trapping de erro:

 open (INPUT_FILE, "<$input_file") || die "Can't open $input_file: $!\n"; 

Eu sei que você também pode atribuir um filehandle a uma variável, então ao invés de usar “INPUT_FILE” como eu fiz acima, eu poderia ter usado $ input_filehandle – é assim melhor?

Para ler um arquivo, se for pequeno, há algo errado com globbing, como este?

 my @array = ; 

ou

 my $file_contents = join( "\n",  ); 

ou você deve sempre percorrer, assim:

 my @array; while () { push(@array, $_); } 

Eu sei que existem tantas maneiras de realizar coisas em perl, só estou querendo saber se existem methods preferenciais / padrão de abrir e ler em um arquivo?

Não há padrões universais, mas há razões para preferir um ou outro. Minha forma preferida é esta:

 open( my $input_fh, "<", $input_file ) || die "Can't open $input_file: $!"; 

As razões são:

  • Você relata erros imediatamente. (Substitua "morrer" por "avisar" se é isso que você quer.)
  • O seu filehandle agora é contado por referência, então, quando você não estiver usando, ele será automaticamente fechado. Se você usar o nome global INPUT_FILEHANDLE, será necessário fechar o arquivo manualmente ou ele permanecerá aberto até que o programa saia.
  • O indicador do modo de leitura "<" é separado do $ input_file, aumentando a legibilidade.

O seguinte é ótimo se o arquivo é pequeno e você sabe que quer todas as linhas:

 my @lines = <$input_fh>; 

Você pode até fazer isso, se precisar processar todas as linhas como uma única string:

 my $text = join('', <$input_fh>); 

Para arquivos longos, convém iterar as linhas com while ou usar a leitura.

Se você quiser o arquivo inteiro como uma única string, não há necessidade de iterá-lo.

 use strict; use warnings; use Carp; use English qw( -no_match_vars ); my $data = q{}; { local $RS = undef; # This makes it just read the whole thing, my $fh; croak "Can't open $input_file: $!\n" if not open $fh, '<', $input_file; $data = <$fh>; croak 'Some Error During Close :/ ' if not close $fh; } 

O acima satisfaz o perlcritic --brutal , que é uma boa maneira de testar as ‘melhores práticas’ :). $input_file ainda não está definido aqui, mas o resto é kosher.

Ter que escrever “ou morrer” em todos os lugares me deixa louco. Minha maneira preferida de abrir um arquivo se parece com isso:

 use autodie; open(my $image_fh, '<', $filename); 

Enquanto isso é muito pouco digitação, há um monte de coisas importantes para observar o que está acontecendo:

  • Estamos usando o autodie pragma, o que significa que todos os built-ins do Perl lançarão uma exceção se algo der errado. Ele elimina a necessidade de escrever or die ... em seu código, ele produz mensagens de erro amigáveis, legíveis por humanos, e tem escopo léxico. Está disponível no CPAN.

  • Estamos usando a versão de três argumentos do open. Isso significa que mesmo se tivermos um nome de arquivo engraçado contendo caracteres como < , > ou | Perl ainda fará a coisa certa. No meu tutorial Perl Security, na OSCON, mostrei várias maneiras de open argumento 2 para se comportar mal. As notas deste tutorial estão disponíveis para download gratuito na Perl Training Australia .

  • Estamos usando um identificador de arquivo escalar. Isso significa que não seremos coincidentemente fechar o identificador de arquivo de outro usuário com o mesmo nome, o que pode acontecer se usarmos identificadores de arquivo de pacote. Isso também significa que a strict pode identificar erros de digitação e que nossa alça de arquivo será limpa automaticamente se ficar fora do escopo.

  • Estamos usando um identificador de arquivos significativo . Neste caso, parece que vamos escrever para uma imagem.

  • O identificador de arquivo termina com _fh . Se nos virmos usando-o como um escalar normal, sabemos que provavelmente é um erro.

Se seus arquivos são pequenos o suficiente para que seja possível ler tudo na memory, use File :: Slurp . Ele lê e grava arquivos completos com uma API muito simples, além de fazer toda a verificação de erros para que você não precise fazer isso.

Não há melhor maneira de abrir e ler um arquivo. É a pergunta errada a se fazer. O que há no arquivo? Quantos dados você precisa em algum momento? Você precisa de todos os dados de uma só vez? O que você precisa fazer com os dados? Você precisa descobrir isso antes de pensar em como abrir e ler o arquivo.

Há algo que você está fazendo agora causando problemas? Se não, você não tem problemas melhores para resolver? 🙂

A maior parte da sua pergunta é meramente syntax, e tudo isso é respondido na documentação do Perl (especialmente ( perlopentut ). Você também pode gostar de pegar o Learning Perl , que responde a maioria dos problemas que você tem em sua pergunta.

Boa sorte, 🙂

É verdade que existem tantas maneiras de abrir um arquivo em Perl quanto existem

 $files_in_the_known_universe * $perl_programmers 

… mas ainda é interessante ver quem normalmente faz isso de qualquer maneira. Minha forma preferida de fazer slurping (ler todo o arquivo de uma só vez) é:

 use strict; use warnings; use IO::File; my $file = shift @ARGV or die "what file?"; my $fh = IO::File->new( $file, '<' ) or die "$file: $!"; my $data = do { local $/; <$fh> }; $fh->close(); # If you didn't just run out of memory, you have: printf "%d characters (possibly bytes)\n", length($data); 

E quando vai linha por linha:

 my $fh = IO::File->new( $file, '<' ) or die "$file: $!"; while ( my $line = <$fh> ) { print "Better than cat: $line"; } $fh->close(); 

Advertência: é claro, estas são apenas as abordagens que me comprometi com a memory muscular para o trabalho cotidiano, e elas podem ser radicalmente inadequadas para o problema que você está tentando resolver.

Para OO, gosto de:

 use FileHandle; ... my $handle = FileHandle->new( "< $file_to_read" ); croak( "Could not open '$file_to_read'" ) unless $handle; ... my $line1 = <$handle>; my $line2 = $handle->getline; my @lines = $handle->getlines; $handle->close; 

Uma vez usei o

 open (FILEIN, "<", $inputfile) or die "..."; my @FileContents = ; close FILEIN; 

clichê regularmente. Hoje em dia, eu uso File::Slurp para arquivos pequenos que eu quero armazenar completamente na memory, e Tie::File para arquivos grandes que eu quero endereçar de forma escalável e / ou arquivos que eu quero mudar no lugar.

Leia todo o arquivo $ do arquivo na variável $ text com uma única linha

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

ou como uma function

 $text = load_file($file); sub load_file {local(@ARGV, $/) = @_; <>} 

Se estes programas são apenas para a sua produtividade, tudo funciona! Construa o máximo de tratamento de erros que você acha que precisa.

Ler um arquivo inteiro, se for grande, pode não ser a melhor maneira de fazer as coisas a longo prazo, portanto, talvez você queira processar as linhas à medida que elas chegam, em vez de carregá-las em uma matriz.

Uma dica que recebi de um dos capítulos de O Programador Pragmático (Hunt & Thomas) é que você pode querer que o script salve um backup do arquivo para você antes de ir para o trabalho de fatiar e cortar.

O || O operador tem precedência mais alta, por isso é avaliado primeiro antes de enviar o resultado para “abrir” … No código que você mencionou, use o operador “ou”, e você não teria esse problema.

 open INPUT_FILE, "<$input_file" or die "Can't open $input_file: $!\n"; 

Damian Conway faz assim:

 $data = readline!open(!((*{!$_},$/)=\$_)) for "filename"; 

Mas eu não recomendo isso para você.