[첫화면으로]Perl/파일

마지막으로 [b]

1. 기본적인 입출력
1.1. 읽기쓰기 모드에서 읽기와 쓰기의 전환
1.2. chomp
1.3. 인자 3개 형태의 open을 쓰자
1.4. 파일핸들도 렉시컬 변수를 쓸 수 있다
2. <ARGV>
3. $/
4. 파일 핸들끼리의 할당
4.1. 파일 핸들을 서브루틴의 인자로 넘기기
5. 바이너리 파일 입출력
6. select
7. 버퍼링
8. 디렉토리
8.1. chdir
8.2. Globbing
8.3. Directory Handle
9. 파일 관련 테스트 연산자
10. stat, lstat
11. special underscore filehandle
12. 파일, 디렉토리 관련 명령어와 함수
13. 인코딩 지정
14. 스트링 변수를 파일처럼 읽거나 쓰기
15. 기타
16. Comments

1. 기본적인 입출력

한 줄씩 읽는 예제:

open my $fileHandle, "<", $fileName ) or die "Cannot open $fileName: $!";
while( $aLine = <$fileHandle> )
{
  print $aLine;
}
close $fileHandle;

# 변수를 생략하면 $_ 사용
while (<$fileHandle>) {    # (defined ($_ = <$fileHandle>))
  print "$_";
}

배열 변수를 써서 통채로 읽는 예제: (파일이 크면 메모리를 많이 소모할 수 있으므로 주의)

open my $fileHandle, "<", $fileName or die "Cannot open $fileName: $!";
@allLines = <$fileHandle>;
close $fileHandle;

"input record separator" 변수 $/의 값을 바꿈으로써 스칼라 변수에 파일 전체를 담는 경우. ($/의 기본값은 "\n")

local $/ = undef;
open my $fileHandle, "<", $fileName or die "Cannot open $fileName: $!";
$allLines = <$fileHandle>;
close $fileHandle;

파일을 통채로 읽거나 쓰는 것은 Cpan:File::Slurp 모듈을 쓰면 편하다.

1.1. 읽기쓰기 모드에서 읽기와 쓰기의 전환

"+<", "+>", "+>>" 를 사용하여 열 경우에, 읽는 동작과 쓰는 동작을 번갈아가며 수행할 경우 예상치 않은 결과가 나올 수 있다([예]) 읽기와 쓰기 동작 사이에는 seek를 써서 제대로 파일포지션 포인터를 세팅해 주어야 하는 듯.

1.2. chomp

스트링 뒤의 new line "\n"을 제거1 정확히는, $/변수의 값을 제거2
$line = <STDIN>;
chomp $line;
# 한 줄로
chomp ($line = <STDIN>);

## 리스트의 경우는, 각 엘리먼트의 "\n"을 일괄 제거
chomp (@lines = <STDIN>);

1.3. 인자 3개 형태의 open을 쓰자

파일명에 잘못된 문자(부등호 등)가 포함되거나, 악의적으로 파이프 등을 사용하는 것에 대비해서, 인자 3개 형태로 사용하자.

open FH, $filename;       # 이건 위험
open FH, "< $filename";   # 입력의 경우 "<"가 없어도 되지만 명시하는게 안전
# perl 5.6 이상부터는 별개의 인자로 줄 수 있음
open FH, "<", $filename;  # 이것을 권장

1.4. 파일핸들도 렉시컬 변수를 쓸 수 있다

open FH, "<", $filename;      # FH 는 전역적인 파일핸들
open my $fh, "<", $filename;  # $fh 는 렉시컬 변수. 권장

2. <ARGV>

<ARGV>또는 <> - 명령행 인자로 들어온 스트링을 파일명으로 취급하여 모든 파일들을 열고 읽음. 인자가 없으면 표준입력을 읽음.

현재 읽고 있는 파일의 이름은 $ARGV 에 담긴다.

#!/usr/bin/perl
# nl3.plx
use warnings;
use strict;

my $lineno;
my $current = "";

while (<>) {
   if ($current ne $ARGV) {
      $current = $ARGV;
      print "\n\t\tFile: $ARGV\n\n";
      $lineno=1;
   }

   print $lineno++;
   print ": $_";
}

3. $/

4. 파일 핸들끼리의 할당

if (defined $input) {
   open INPUT, $input or die "Couldn't open file $input: $!\n";
} else {
   *INPUT = *STDIN;   # typeglob을 사용해야 함
}

4.1. 파일 핸들을 서브루틴의 인자로 넘기기

# typeglob 사용
sub say_hello {
   *WHERE = shift;
   print WHERE "Hi there!\n";
}
say_hello(*STDOUT);

## 또는
sub say_hello {
   my $fh = shift;  # 일반 변수에
   print $fh "Hi there!\n";
}
say_hello(*STDOUT); # 호출하는 쪽에서는 typeglob

5. 바이너리 파일 입출력

binmode FILEHANDLE;

6. select

writeprint 등 출력에 사용되는 디폴트 파일 핸들을 지정하며, 현재의 디폴트 파일 핸들을 반환한다.

select LOG;
print "blah blah...\n";   # LOG에 해당하는 파일로 출력된다.

select STDOUT;  # 표준출력으로 복원

7. 버퍼링

select 로 지정된 파일핸들에 대하여
$| = 1;
for (1...20) {
   print ".";   # 버퍼링이 사용될 경우, 20초 후에 한꺼번에 20개의 "."이 출력된다.
   sleep 1;
}
print "\n";

[Suffering from Buffering?] 글도 참고

8. 디렉토리

8.1. chdir

chdir - working directory 변경5

8.2. Globbing

Globbing - 파일명 패턴 확장6
my @all_files = glob "*";
my @pm_files = glob "*.pm";
my @all_files_including_dot = glob ".* *";  # 패턴들은 공백으로 구분
# 또는
my @all_files = <*>;

8.3. Directory Handle

opendir로 열고, readdir로 읽고, closedir로 닫는다7
opendir DH, "." or die "Couldn't open the current directory: $!";
while ($_ = readdir(DH)) {   # readdir은 파일명을 하나씩 반환
        next if $_ eq "." or $_ eq "..";
        print $_, " " x (30-length($_));
        print "d" if -d $_;
        print "r" if -r _;   # "_"는 "마지막으로 테스트한 파일"을 의미
        # ...
}
closedir DH;
}

9. 파일 관련 테스트 연산자

파일 속성 테스트 연산자들8
File test Meaning
-r File or directory is readable by this (effective) user or group
-w File or directory is writable by this (effective) user or group
-x File or directory is executable by this (effective) user or group
-o File or directory is owned by this (effective) user
-R File or directory is readable by this real user or group
-W File or directory is writable by this real user or group
-X File or directory is executable by this real user or group
-O File or directory is owned by this real user
-e File or directory name exists
-z File exists and has zero size (always false for directories)
-s File or directory exists and has nonzero size (the value is the size in bytes)
-f Entry is a plain file
-d Entry is a directory
-l Entry is a symbolic link
-S Entry is a socket
-p Entry is a named pipe (a "fifo")
-b Entry is a block-special file (like a mountable disk)
-c Entry is a character-special file (like an I/O device)
-u File or directory is setuid
-g File or directory is setgid
-k File or directory has the sticky bit set
-t The filehandle is a TTY (as reported by the isatty( ) system function; filenames can't be tested by this test)
-T File looks like a "text" file
-B File looks like a "binary" file
-M Modification age (measured in days)
-A Access age (measured in days)
-C Inode-modification age (measured in days)

10. stat, lstat

심볼릭 링크의 경우 stat은 링크가 가리키는 파일에 대한 정보를 얻어온다. 링크 자체의 정보를 얻고 싶다면 lstat을 사용9
    my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev,
      $size, $atime, $mtime, $ctime, $blksize, $blocks)
        = stat($filename);

11. special underscore filehandle

동일한 파일에 여러 번 파일 테스트 연산자,stat,lstat 연산을 수행하는 경우, "_"를 인자로 주면 기존 연산 시 얻어온 정보를 재사용한다. (서브루틴 등에서 stat을 부르는 바람에 자신도 모르는 사이에 대상 파일이 바뀌었을지 모르니 주의)10
push @big_old_files, $_
        if (-s) > 100_000 and -A _ > 90;        # -A 의 인자로 "_"

참고: -l _의 경우는 가장 최근에 파일 정보를 얻어온 방법이 lstat이어야만 의미가 있다. stat은 심볼릭 링크의 경우 실제 타겟 파일을 찾아가서 정보를 얻어오므로 -l 연산의 결과가 결코 참이 되지 않기 때문이다. 직전에 수행한 게 lstat 이 아닐 경우 "The stat preceding -l _ wasn't an lstat"라는 에러가 난다.11

12. 파일, 디렉토리 관련 명령어와 함수

                   $cnt = unlink ’a’, ’b’, ’c’;
                   unlink @goners;
                   unlink <*.bak>;

13. 인코딩 지정

파일 입출력 Layer에서 인코딩/디코딩 변환을 지정할 수 있음12

# UTF-8로 저장된 파일을 읽어서 디코드
open my $fh, '<:utf8', 'file.txt';

# UTF-8로 저장된 파일을 읽어서 디코드 - 정합성 체크까지
open my $fh, '<:encoding(UTF-8)', 'file.txt';

# EUC-KR로 저장된 파일을 읽어서 디코드
open my $fh, '<:encoding(EUC-KR)', 'file.txt';

# UTF-8로 인코드하여 저장
open my $fh, '>:utf8', 'file.txt';

# 이미 열려 있는 파일 핸들은 binmode 로 지정 가능
binmode STDIN,':utf8';

14. 스트링 변수를 파일처럼 읽거나 쓰기

Perl 5.8 부터 지원

my $string;
open my $fh, ">", \ $string;

# 위 두 줄을 아래처럼 쓸 수도 있음
open my $fh, ">", \ my $string;

# 일반적으로 파일을 다루듯이 쓸 수 있음
print $fh "Hello";

단, 파일 핸들과 연결되어 있는 상태의 스트링 변수에 다른 형태로 접근할 경우 의도하지 않은 결과가 나오니 주의.13

15. 기타

16. Comments

이름:  
Homepage:
내용:
 


컴퓨터분류
각주:
1. Learning Perl, Chapter 03
2. 3. 4. [Just Another Perl Article]
5. 6. 7. 8. 9. 10. Learning Perl, Chapter 11
11. [“The stat preceding -l _ wasn’t an lstat” | Learning Perl]
12. [Unicode in Perl - aero님의 노트]
13. [Avoid modifying scalars connected to string filehandles | The Effective Perler]

마지막 편집일: 2015-6-2 11:11 am (변경사항 [d])
10943 hits | Permalink | 변경내역 보기 [h] | 페이지 소스 보기