Programing

Perl에서 전체 파일을 문자열로 읽는 방법은 무엇입니까?

crosscheck 2020. 7. 28. 07:54
반응형

Perl에서 전체 파일을 문자열로 읽는 방법은 무엇입니까?


하나의 큰 긴 문자열로 .html 파일을 열려고합니다. 이것이 내가 가진 것입니다 :

open(FILE, 'index.html') or die "Can't read file 'filename' [$!]\n";  
$document = <FILE>; 
close (FILE);  
print $document;

결과 :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN

그러나 결과가 다음과 같이 표시되기를 원합니다.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

이렇게하면 전체 문서를보다 쉽게 ​​검색 할 수 있습니다.


더하다:

 local $/;

파일 핸들에서 읽기 전에. 전체 파일을 한 번에 읽을 수있는 방법을 참조하십시오 . 또는

$ perldoc -q "전체 파일"

참조 파일 핸들과 관련된 변수perldoc perlvarperldoc -f local.

또한 서버에 스크립트를 넣을 수 있으면 원하는 모든 모듈을 가질 수 있습니다. 자체 모듈 / 라이브러리 디렉토리를 유지하는 방법을 참조하십시오 . .

또한, Path :: Class :: File을 사용하면 문지르 거나 뿌릴 수 있습니다.

경로 : 작은이 같은 더 편리한 방법을 제공합니다 slurp, slurp_raw,slurp_utf8 뿐만 아니라 spew대응을.


나는 이렇게 할 것입니다 :

my $file = "index.html";
my $document = do {
    local $/ = undef;
    open my $fh, "<", $file
        or die "could not open $file: $!";
    <$fh>;
};

3 인수 버전의 open을 사용하십시오. 기존의 2 개 (또는 1 개) 인수 버전보다 훨씬 안전합니다. 또한 어휘 파일 핸들 사용에 유의하십시오. 어휘 파일 핸들은 여러 가지 이유로 오래된 베어 워드 변형보다 좋습니다. 우리는 여기서 그것들 중 하나를 이용하고 있습니다 : 그들은 범위를 벗어날 때 닫힙니다.


파일 :: 소리내어 먹는다 :

use File::Slurp;
my $text = read_file('index.html');

예, CPAN도 사용할 수 있습니다 .


모든 게시물이 약간 비 관용적입니다. 관용구는 :

open my $fh, '<', $filename or die "error opening $filename: $!";
my $data = do { local $/; <$fh> };

대부분 $ /를 설정할 필요가 없습니다 undef.


에서 perlfaq5 : 어떻게 한 번에 모든 전체 파일을 읽을 수 있습니까? :


File :: Slurp 모듈을 사용하여 한 번에 수행 할 수 있습니다.

use File::Slurp;

$all_of_it = read_file($filename); # entire file in scalar
@all_lines = read_file($filename); # one line per element

파일의 모든 줄을 처리하기위한 일반적인 Perl 방식은 한 번에 한 줄씩 수행하는 것입니다.

open (INPUT, $file)     || die "can't open $file: $!";
while (<INPUT>) {
    chomp;
    # do something with $_
    }
close(INPUT)            || die "can't close $file: $!";

이것은 전체 파일을 메모리에 줄 배열로 읽어서 한 번에 한 요소 씩 처리하는 것보다 훨씬 더 효율적입니다. 누군가가 이것을 볼 때마다 :

@lines = <INPUT>;

한 번에 모든 것을로드해야하는 이유에 대해 길고 열심히 생각해야합니다. 확장 가능한 솔루션이 아닙니다. 표준 Tie :: File 모듈 또는 DB_File 모듈의 $ DB_RECNO 바인딩을 사용하는 것이 더 재미있을 수도 있습니다. 이렇게하면 배열을 파일에 묶어 배열이 실제로 파일의 해당 행에 액세스 할 수 있습니다. .

전체 파일 핸들 내용을 스칼라로 읽을 수 있습니다.

{
local(*INPUT, $/);
open (INPUT, $file)     || die "can't open $file: $!";
$var = <INPUT>;
}

That temporarily undefs your record separator, and will automatically close the file at block exit. If the file is already open, just use this:

$var = do { local $/; <INPUT> };

For ordinary files you can also use the read function.

read( INPUT, $var, -s INPUT );

The third argument tests the byte size of the data on the INPUT filehandle and reads that many bytes into the buffer $var.


A simple way is:

while (<FILE>) { $document .= $_ }

Another way is to change the input record separator "$/". You can do it locally in a bare block to avoid changing the global record separator.

{
    open(F, "filename");
    local $/ = undef;
    $d = <F>;
}

Either set $/ to undef (see jrockway's answer) or just concatenate all the file's lines:

$content = join('', <$fh>);

It's recommended to use scalars for filehandles on any Perl version that supports it.


Another possible way:

open my $fh, '<', "filename";
read $fh, my $string, -s $fh;
close $fh;

You're only getting the first line from the diamond operator <FILE> because you're evaluating it in scalar context:

$document = <FILE>; 

In list/array context, the diamond operator will return all the lines of the file.

@lines = <FILE>;
print @lines;

I would do it in the simplest way, so anyone can understand what happens, even if there are smarter ways:

my $text = "";
while (my $line = <FILE>) {
    $text .= $line;
}

open f, "test.txt"
$file = join '', <f>

<f> - returns an array of lines from our file (if $/ has the default value "\n") and then join '' will stick this array into.


This is more of a suggestion on how NOT to do it. I've just had a bad time finding a bug in a rather big Perl application. Most of the modules had its own configuration files. To read the configuration files as-a-whole, I found this single line of Perl somewhere on the Internet:

# Bad! Don't do that!
my $content = do{local(@ARGV,$/)=$filename;<>};

It reassigns the line separator as explained before. But it also reassigns the STDIN.

This had at least one side effect that cost me hours to find: It does not close the implicit file handle properly (since it does not call closeat all).

For example, doing that:

use strict;
use warnings;

my $filename = 'some-file.txt';

my $content = do{local(@ARGV,$/)=$filename;<>};
my $content2 = do{local(@ARGV,$/)=$filename;<>};
my $content3 = do{local(@ARGV,$/)=$filename;<>};

print "After reading a file 3 times redirecting to STDIN: $.\n";

open (FILE, "<", $filename) or die $!;

print "After opening a file using dedicated file handle: $.\n";

while (<FILE>) {
    print "read line: $.\n";
}

print "before close: $.\n";
close FILE;
print "after close: $.\n";

results in:

After reading a file 3 times redirecting to STDIN: 3
After opening a file using dedicated file handle: 3
read line: 1
read line: 2
(...)
read line: 46
before close: 46
after close: 0

The strange thing is, that the line counter $. is increased for every file by one. It's not reset, and it does not contain the number of lines. And it is not reset to zero when opening another file until at least one line is read. In my case, I was doing something like this:

while($. < $skipLines) {<FILE>};

Because of this problem, the condition was false because the line counter was not reset properly. I don't know if this is a bug or simply wrong code... Also calling close; oder close STDIN; does not help.

I replaced this unreadable code by using open, string concatenation and close. However, the solution posted by Brad Gilbert also works since it uses an explicit file handle instead.

The three lines at the beginning can be replaced by:

my $content = do{local $/; open(my $f1, '<', $filename) or die $!; my $tmp1 = <$f1>; close $f1 or die $!; $tmp1};
my $content2 = do{local $/; open(my $f2, '<', $filename) or die $!; my $tmp2 = <$f2>; close $f2 or die $!; $tmp2};
my $content3 = do{local $/; open(my $f3, '<', $filename) or die $!; my $tmp3 = <$f3>; close $f3 or die $!; $tmp3};

which properly closes the file handle.


Use

 $/ = undef;

before $document = <FILE>;. $/ is the input record separator, which is a newline by default. By redefining it to undef, you are saying there is no field separator. This is called "slurp" mode.

Other solutions like undef $/ and local $/ (but not my $/) redeclare $/ and thus produce the same effect.


You could simply create a sub-routine:

#Get File Contents
sub gfc
{
    open FC, @_[0];
    join '', <FC>;
}

I don't know if it's good practice, but I used to use this:

($a=<F>);

These are all good answers. BUT if you're feeling lazy, and the file isn't that big, and security is not an issue (you know you don't have a tainted filename), then you can shell out:

$x=`cat /tmp/foo`;    # note backticks, qw"cat ..." also works

You can use cat in Linux:

@file1=\`cat /etc/file.txt\`;

참고URL : https://stackoverflow.com/questions/953707/in-perl-how-can-i-read-an-entire-file-into-a-string

반응형