-1,24 +1,349 |
화일 관련 연산자. |
* -e 존재하는가? |
* -z 크기가 0인가? |
* -s 화일크기가 0이 아닌가? (파일의 크기 리턴) |
* -f regular file |
* -d directory |
* -T 텍스트 화일 |
* -B 바이너리 화일 |
* -M 화일이 생성된 지 몇일이 지났는가? (0부터) |
|
화일입출력 |
* open( fileHandle, "filename" ); 로 열고, |
** "<화일명" , "화일명" : 읽기모드 |
** ">화일명" : 쓰기모드 |
** ">>화일명" : 추가모드 |
** "+<화일명" : 읽기, 쓰기 |
<toc> |
|
== # 기본적인 입출력 == |
* open FILEHANDLE, MODE, EXPR |
** EXPR 은 주로 파일명 |
** MODE |
*** <code><</code> 또는 없음 : 읽기모드 |
*** <code>></code> : 쓰기모드. 파일이 존재할 경우 내용을 지움 |
*** <code>>></code> : 추가모드. 파일이 존재할 경우 마지막에 내용을 추가함 |
*** <code>+<</code> : 읽기, 쓰기 |
*** <code>+></code> : 읽기, 쓰기. 파일이 존재할 경우 내용을 지움 |
*** <code>+>></code> : 읽기, 추가하기 |
*** <code>|-</code> : 출력 파이프 |
*** <code>-|</code> : 입력 파이프 |
** open에 실패하면 $! 변수에 에러 내용이 담긴다. |
* 읽거나 쓰고 |
** @allLine = <fileHandle>; 화일 전부를 읽기 |
** @allLine = <fileHandle>; 파일 전부를 읽기 |
** $aLine = <fileHandle>; 한 줄 읽기 |
** print fileHandle "안녕"; 출력 |
* close( fileHandle ); 로 닫는다. |
|
한 줄씩 읽는 예제: |
{{{#!vim perl |
open my $fileHandle, "<", $fileName ) or die "Cannot open $fileName: $!"; |
while( $aLine = <$fileHandle> ) |
{ |
print $aLine; |
} |
close $fileHandle; |
|
# 변수를 생략하면 $_ 사용 |
while (<$fileHandle>) { # (defined ($_ = <$fileHandle>)) |
print "$_"; |
} |
}}} |
|
배열 변수를 써서 통채로 읽는 예제: (파일이 크면 메모리를 많이 소모할 수 있으므로 주의) |
{{{#!vim perl |
open my $fileHandle, "<", $fileName or die "Cannot open $fileName: $!"; |
@allLines = <$fileHandle>; |
close $fileHandle; |
}}} |
|
"input record separator" 변수 $/의 값을 바꿈으로써 스칼라 변수에 파일 전체를 담는 경우. ($/의 기본값은 "\n") |
{{{#!vim perl |
local $/ = undef; |
open my $fileHandle, "<", $fileName or die "Cannot open $fileName: $!"; |
$allLines = <$fileHandle>; |
close $fileHandle; |
}}} |
|
|
파일을 통채로 읽거나 쓰는 것은 Cpan:File::Slurp 모듈을 쓰면 편하다. |
|
|
=== # 읽기쓰기 모드에서 읽기와 쓰기의 전환 === |
|
"+<", "+>", "+>>" 를 사용하여 열 경우에, 읽는 동작과 쓰는 동작을 번갈아가며 수행할 경우 예상치 않은 결과가 나올 수 있다([http://cafe.naver.com/perlstudy/1244 예]) 읽기와 쓰기 동작 사이에는 <code>seek</code>를 써서 제대로 파일포지션 포인터를 세팅해 주어야 하는 듯. |
|
|
|
=== # chomp === |
스트링 뒤의 new line "\n"을 제거<footnote(Learning Perl, Chapter 03)> 정확히는, $/변수의 값을 제거<footnote([http://japhy.perlmonk.org/articles/misc/files.html Just Another Perl Article])> |
{{{#!vim perl |
$line = <STDIN>; |
chomp $line; |
# 한 줄로 |
chomp ($line = <STDIN>); |
|
## 리스트의 경우는, 각 엘리먼트의 "\n"을 일괄 제거 |
chomp (@lines = <STDIN>); |
}}} |
|
=== # 인자 3개 형태의 open을 쓰자 === |
|
파일명에 잘못된 문자(부등호 등)가 포함되거나, 악의적으로 파이프 등을 사용하는 것에 대비해서, 인자 3개 형태로 사용하자. |
{{{#!vim perl |
open FH, $filename; # 이건 위험 |
open FH, "< $filename"; # 입력의 경우 "<"가 없어도 되지만 명시하는게 안전 |
# perl 5.6 이상부터는 별개의 인자로 줄 수 있음 |
open FH, "<", $filename; # 이것을 권장 |
}}} |
|
|
|
=== # 파일핸들도 렉시컬 변수를 쓸 수 있다 === |
|
{{{#!vim perl |
open FH, "<", $filename; # FH 는 전역적인 파일핸들 |
open my $fh, "<", $filename; # $fh 는 렉시컬 변수. 권장 |
}}} |
|
|
|
|
|
== # <ARGV> == |
<code><ARGV></code>또는 <code><></code> - 명령행 인자로 들어온 스트링을 파일명으로 취급하여 모든 파일들을 열고 읽음. 인자가 없으면 표준입력을 읽음. |
|
현재 읽고 있는 파일의 이름은 $ARGV 에 담긴다. |
|
{{{#!vim perl |
#!/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 ": $_"; |
} |
}}} |
|
== # $/ == |
* $/ = ""; - blank line을 구분자로 함 (단락 단위로 읽는다고 볼 수 있다) |
* $/ = undef; - file 내용 전체를 하나의 스칼라로 읽음 |
* $/ = \1024; (양수의 레퍼런스) - 한 번에 1024바이트를 읽음<footnote([http://japhy.perlmonk.org/articles/misc/files.html Just Another Perl Article])> |
* chomp 의 역할은 인자의 제일 뒤에 $/ 변수의 값이 있는 경우 그것을 제거<footnote([http://japhy.perlmonk.org/articles/misc/files.html Just Another Perl Article])> |
== # 파일 핸들끼리의 할당 == |
{{{#!vim perl |
if (defined $input) { |
open INPUT, $input or die "Couldn't open file $input: $!\n"; |
} else { |
*INPUT = *STDIN; # typeglob을 사용해야 함 |
} |
}}} |
|
=== # 파일 핸들을 서브루틴의 인자로 넘기기 === |
{{{#!vim perl |
# 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 |
}}} |
|
== # 바이너리 파일 입출력 == |
{{{#!vim perl |
binmode FILEHANDLE; |
}}} |
|
== # select == |
<code>write</code>나 <code>print</code> 등 출력에 사용되는 디폴트 파일 핸들을 지정하며, 현재의 디폴트 파일 핸들을 반환한다. |
|
{{{#!vim perl |
select LOG; |
print "blah blah...\n"; # LOG에 해당하는 파일로 출력된다. |
|
select STDOUT; # 표준출력으로 복원 |
}}} |
|
== # 버퍼링 == |
select 로 지정된 파일핸들에 대하여 |
* $| = 0; - 운영체제의 버퍼링 사용 (기본값) |
* $| = 1; - 버퍼링 사용하지 않음 |
{{{#!vim perl |
$| = 1; |
for (1...20) { |
print "."; # 버퍼링이 사용될 경우, 20초 후에 한꺼번에 20개의 "."이 출력된다. |
sleep 1; |
} |
print "\n"; |
}}} |
|
[http://perl.plover.com/FAQs/Buffering.html Suffering from Buffering?] 글도 참고 |
|
|
|
== # 디렉토리 == |
=== # chdir === |
chdir - working directory 변경<footnote(Learning Perl, Chapter 11)> |
* 변경된 디렉토리는 자식 프로세스에 상속됨 |
* 파라메터가 생략되었을 경우는 '''$_을 쓰는 게 아니라''' 현재 사용자의 홈 디렉토리로 변경 시도 |
* 쉘의 cd에서 가능한 ~username 형식은 지원하지 않는다. - 이것은 OS가 아니라 쉘의 기능 |
|
=== # Globbing === |
Globbing - 파일명 패턴 확장<footnote(Learning Perl, Chapter 11)> |
{{{#!vim perl |
my @all_files = glob "*"; |
my @pm_files = glob "*.pm"; |
my @all_files_including_dot = glob ".* *"; # 패턴들은 공백으로 구분 |
# 또는 |
my @all_files = <*>; |
}}} |
|
=== # Directory Handle === |
opendir로 열고, readdir로 읽고, closedir로 닫는다<footnote(Learning Perl, Chapter 11)> |
* readdir의 리턴값은 경로명을 제외한 파일명만 들어 있으니 주의 |
{{{#!vim perl |
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; |
} |
}}} |
|
== # 파일 관련 테스트 연산자 == |
파일 속성 테스트 연산자들<footnote(Learning Perl, Chapter 11)> |
|< 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) || |
|
== # stat, lstat == |
심볼릭 링크의 경우 stat은 링크가 가리키는 파일에 대한 정보를 얻어온다. 링크 자체의 정보를 얻고 싶다면 lstat을 사용<footnote(Learning Perl, Chapter 11)> |
{{{#!vim perl |
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, |
$size, $atime, $mtime, $ctime, $blksize, $blocks) |
= stat($filename); |
}}} |
|
== # special underscore filehandle == |
동일한 파일에 여러 번 파일 테스트 연산자,stat,lstat 연산을 수행하는 경우, "_"를 인자로 주면 기존 연산 시 얻어온 정보를 재사용한다. (서브루틴 등에서 stat을 부르는 바람에 자신도 모르는 사이에 대상 파일이 바뀌었을지 모르니 주의)<footnote(Learning Perl, Chapter 11)> |
{{{#!vim perl |
push @big_old_files, $_ |
if (-s) > 100_000 and -A _ > 90; # -A 의 인자로 "_" |
}}} |
|
|
참고: <code>-l _</code>의 경우는 가장 최근에 파일 정보를 얻어온 방법이 <code>lstat</code>이어야만 의미가 있다. <code>stat</code>은 심볼릭 링크의 경우 실제 타겟 파일을 찾아가서 정보를 얻어오므로 -l 연산의 결과가 결코 참이 되지 않기 때문이다. 직전에 수행한 게 lstat 이 아닐 경우 "The stat preceding -l _ wasn't an lstat"라는 에러가 난다.<footnote([http://www.learning-perl.com/?p=395 “The stat preceding -l _ wasn’t an lstat” | Learning Perl])> |
|
|
|
== # 파일, 디렉토리 관련 명령어와 함수 == |
* rename OLDNAME, NEWNAME |
* unlink LIST |
{{{#!vim perl |
$cnt = unlink ’a’, ’b’, ’c’; |
unlink @goners; |
unlink <*.bak>; |
}}} |
* link OLDFILE, NEWFILE - 하드 링크 |
* symlink OLDFILE, NEWFILE - 심볼릭 링크 |
** readlink EXPR - 심볼릭 링크의 값을 읽음 |
|
* mkdir FILENAME, MASK |
* rmdir FILENAME |
** 빈 디렉토리만 삭제 가능 |
** File::Path 모듈의 rmtree를 쓰면 편하다 |
|
* chmod LIST |
** ex) chmod 0755, "fred", "barney"; |
* chown LIST |
** ex) chown $user, $group, @filenames; |
** user ID와 group ID는 숫자. 이름으로부터 얻고 싶다면 getpwnam, getgrnam 사용하여 해당 숫자 값을 먼저 얻을 것 |
* utime LIST - 액세스 시각과 수정 시각 변경 |
** ex) utime $atime, $mtime, @filenames; |
|
|
== # 인코딩 지정 == |
|
파일 입출력 Layer에서 인코딩/디코딩 변환을 지정할 수 있음<footnote([http://aero.springnote.com/pages/1053508 Unicode in Perl - aero님의 노트])> |
|
{{{#!vim perl |
# 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'; |
}}} |
|
|
|
== # 스트링 변수를 파일처럼 읽거나 쓰기 == |
|
Perl 5.8 부터 지원 |
|
{{{#!vim perl |
my $string; |
open my $fh, ">", \ $string; |
|
# 위 두 줄을 아래처럼 쓸 수도 있음 |
open my $fh, ">", \ my $string; |
|
# 일반적으로 파일을 다루듯이 쓸 수 있음 |
print $fh "Hello"; |
}}} |
|
단, 파일 핸들과 연결되어 있는 상태의 스트링 변수에 다른 형태로 접근할 경우 의도하지 않은 결과가 나오니 주의.<footnote([http://www.effectiveperlprogramming.com/blog/770 Avoid modifying scalars connected to string filehandles | The Effective Perler])> |
|
|
|
== # 기타 == |
|
* [http://perl.plover.com/FAQs/Buffering.html Suffering from Buffering?] |
|
|
== # Comments == |
|
<longcomments(100)> |
|
|
---- |
[[컴퓨터분류]] |