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:
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ê.