Like Share Discussion Bookmark Smile

J.J. Huang   2021-03-18   Perl   瀏覽次數:

Perl - 第十五章 | Perl 文件操作(I/O)

處理文件的基礎很簡單:將文件句柄與外部實體(通常是文件)相關聯,然後在Perl中使用各種運算符和函數來讀取和更新與文件句柄關聯的資料流中存儲的資料。


文件操作

  • Perl 使用一種叫做文件句柄類型的變量來操作文件。
    • 從文件讀取或者寫入資料需要使用文件句柄。
    • 文件句柄(file handle)是一個I/O連接的名稱。
  • Perl提供了三種文件句柄:
    • STDIN:標準輸入。
    • STDOUT:標準輸出。
    • STDERR:標准出錯輸出。

Perl 中打開文件可以使用以下方式:

1
2
3
4
5
open FILEHANDLE, EXPR
open FILEHANDLE

sysopen FILEHANDLE, FILENAME, MODE, PERMS
sysopen FILEHANDLE, FILENAME, MODE

參數說明:

  • FILEHANDLE:文件句柄,用於存放一個文件唯一標識符。
  • EXPR:文件名及文件訪問類型組成的表達式。
  • MODE:文件訪問類型。
  • PERMS:訪問權限位(permission bits)。

Open 函數

以下程式碼我們使用open函數以只讀的方式<打開文件file.txt:

1
open(DATA, "<file.txt");

註:< 表示只讀方式。

程式碼中的DATA為文件句柄用於讀取文件,以下範例將打開文件並將文件內容輸出:

1
2
3
4
5
6
7
#!/usr/bin/perl

open(DATA, "<file.txt") or die "file.txt 文件無法打開, $!";

while(<DATA>){
print "$_";
}

以下程式碼以寫入>的方式打開文件file.txt:

1
open(DATA, ">file.txt") or die "file.txt 文件無法打開, $!";

註:> 表示寫入方式。

如果你需要以讀寫方式打開文件,可以在><字符前添加+號:

1
open(DATA, "+<file.txt"); or die "file.txt 文件無法打開, $!";

這種方式不會刪除文件原來的內容,如果要刪除,格式如下所示:

1
open DATA, "+>file.txt" or die "file.txt 文件無法打開, $!";

如果要向文件中追加資料,則在追加資料之前,只需要以追加方式打開文件即可:

1
open(DATA,">>file.txt") || die "file.txt 文件無法打開, $!";

註:>> 表示向現有文件的尾部追加資料,如果需要讀取要追加的文件內容可以添加 + 號:

1
open(DATA,"+>>file.txt") || die "file.txt 文件無法打開, $!";

下表列出了不同的訪問模式:

模式 描述
< 或 r 只讀方式打開,將文件指針指向文件頭。
> 或 w 寫入方式打開,將文件指針指向文件頭並將文件大小截為零。如果文件不存在則嘗試建立之。
>> 或 a 寫入方式打開,將文件指針指向文件末尾。如果文件不存在則嘗試建立之。
+< 或 r+ 讀寫方式打開,將文件指針指向文件頭。
+> 或 w+ 讀寫方式打開,將文件指針指向文件頭並將文件大小截為零。如果文件不存在則嘗試建立之。
+>> 或 a+ 讀寫方式打開,將文件指針指向文件末尾。如果文件不存在則嘗試建立之。

Sysopen函數

sysopen函數類似於open函數,只是它們的參數形式不一樣。

以下範例是以讀寫(+<filename)的方式打開文件:

1
sysopen(DATA, "file.txt", O_RDWR);

如果需要在更新文件前清空文件,則寫法如下:

1
sysopen(DATA, "file.txt", O_RDWR|O_TRUNC );

你可以使用O_CREAT來建立一個新的文件,O_WRONLY為只寫模式,O_RDONLY為只讀模式。
The PERMS 參數為八進制屬性值,表示文件建立後的權限,預設為0x666

下表列出了可能的模式值:

模式 描述
O_RDWR 讀寫方式打開,將文件指針指向文件頭。
O_RDONLY 只讀方式打開,將文件指針指向文件頭。
O_WRONLY 寫入方式打開,將文件指針指向文件頭並將文件大小截為零。如果文件不存在則嘗試建立之。
O_CREAT 建立文件
O_APPEND 追加文件
O_TRUNC 將文件大小截為零
O_EXCL 如果使用O_CREAT時文件存在,就返回錯誤訊息,它可以測試文件是否存在
O_NONBLOCK 非阻塞I/O使我們的操作要就成功,要就立即返回錯誤,不被阻塞。

Close 函數

在文件使用完後,要關閉文件,以刷新與文件句柄相關聯的輸入輸出緩衝區,關閉文件的語法如下:

1
2
close FILEHANDLE
close

<FILEHANDLE>為指定的文件句柄,如果成功關閉則返回true。

1
close(DATA) || die "無法關閉文件";

讀寫文件

向文件讀寫訊息有以下幾種不同的方式:

<FILEHANDL> 操作符

從打開的文件句柄讀取訊息的主要方法是操作符。在標量上下文中,它從文件句柄返回單一行。例如:

1
2
3
4
5
#!/usr/bin/perl

print "What is your name?\n";
$name = <STDIN>;
print "Hello $name\n";

這將產生以下結果:

1
2
3
What is your name?
J.J.
Hello J.J.

當我們使用操作符時,它會返回文件句柄中每一行的列表,例如我們可以導入所有的行到數組中。

實現建立import.txt文件,內容如下:

1
2
3
4
$ cat import.txt
1
2
3

讀取import.txt並將每一行放到@lines數組中:

1
2
3
4
5
6
#!/usr/bin/perl

open(DATA,"<import.txt") or die "無法打開資料";
@lines = <DATA>;
print @lines; # 輸出數組內容
close(DATA);

這將產生以下結果:

1
2
3
1
2
3

getc 函數

xgetc函數從指定的<FILEHANDLE>返回單一的字符,如果沒指定返回STDIN:

1
2
getc FILEHANDLE
getc

如果發生錯誤,或在文件句柄在文件末尾,則返回undef。

read 函數

read函數用於從緩衝區的文件句柄讀取訊息。

這個函數用於從文件讀取二進制資料。

1
2
read FILEHANDLE, SCALAR, LENGTH, OFFSET
read FILEHANDLE, SCALAR, LENGTH

參數說明:

  • FILEHANDLE:文件句柄,用於存放一個文件唯一標識符。
  • SCALAR:存貯結果,如果沒有指定OFFSET,資料將放在SCALAR的開頭。否則資料放在SCALAR中的OFFSET字節之後。
  • LENGTH:讀取的內容長度。
  • OFFSET:偏移量。

如果讀取成功返回讀取的字節數,如果在文件結尾返回0,如果發生錯誤返回undef。

對於所有從文件句柄中讀取訊息的函數,在後端主要的寫入函數為print:

1
2
3
print FILEHANDLE LIST
print LIST
print

利用文件句柄和print函數可以把程序運行的結果發給輸出設備(STDOUT:標準輸出),例如:

1
print "Hello World!\n";

複製文件

以下範例我們將打開一個已存在的文件file1.txt,並讀取它的每一行寫入到文件file2.txt中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/perl

# 只讀方式打開文件
open(DATA1, "<file1.txt");

# 打開新文件並寫入
open(DATA2, ">file2.txt");

# 複製資料
while(<DATA1>)
{
print DATA2 $_;
}
close( DATA1 );
close( DATA2 );

重命名文件

以下範例,我們將已存在的文件file1.txt重命名為file2.txt,指定的目錄是在 /Users/morose/Documents/Temp/tutorial/perl/test 下:

1
2
3
#!/usr/bin/perl

rename ("/Users/morose/Documents/Temp/tutorial/perl/file1.txt", "/Users/morose/Documents/Temp/tutorial/perl/test/file2.txt" );

註:函數renames只接受兩個參數,只對已存在的文件進行重命名。

刪除文件

以下範例我們演示瞭如何使用unlink函數來刪除文件:

1
2
#!/usr/bin/perl
unlink ("/Users/morose/Documents/Temp/tutorial/perl/file1.txt");

在文件內定位

你可以使用tell函數來了解文件的當前位置,並使用seek函數來指向文件內的特定位置。

tell 函數

tell函數用於獲取文件位置:

1
2
tell FILEHANDLE
tell

如果指定 FILEHANDLE 該函數返回文件指針的位置,以字節計。如果沒有指定則返回預設選取的文件句柄。

seek 函數

seek函數是通過文件句柄來移動文件讀寫指針的方式來讀取或寫入文件的,以字節為單位進行讀取和寫入:

1
seek FILEHANDLE, POSITION, WHENCE

參數說明:

  • FILEHANDLE:文件句柄,用於存放一個文件唯一標識符。
  • POSITION:表示文件句柄(讀寫位置指針)要移動的字節數。
  • WHENCE:表示文件句柄(讀寫位置指針)開始移動時的起始位置,可以取的值為0、1、2;分別表示文件開頭、當前位置和文件尾。

以下範例為從文件開頭讀取 256 個字節:

1
seek DATA, 256, 0;

文件訊息

你可以使用一系列統稱為-X測試的測試運算符在Perl中非常快速地測試某些功能。例如,要對文件的各種權限進行快速測試,可以使用如下腳本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/perl

my $file = "/Users/morose/Documents/Temp/tutorial/perl/file1.txt";
my (@description, $size);
if (-e $file)
{
push @description, '是一個二進製文件' if (-B _);
push @description, '是一個socket(套接字)' if (-S _);
push @description, '是一個文本文件' if (-T _);
push @description, '是一個特殊塊文件' if (-b _);
push @description, '是一個特殊字符文件' if (-c _);
push @description, '是一個目錄' if (-d _);
push @description, '文件存在' if (-x _);
push @description, (($size = -s _)) ? "$size 字節" : '空';
print "$file 訊息:", join(', ',@description),"\n";
}

這將產生以下結果:

1
/Users/morose/Documents/Temp/tutorial/perl/file1.txt 訊息:是一個文本文件, 文件存在, 49 字節

文件測試操作符如下表所示:

操作符 描述
-A 文件上一次被訪問的時間(單位:天)
-B 是否為二進製文件
-C 文件的(inode)索引節點修改時間(單位:天)
-M 文件上一次被修改的時間(單位:天)
-O 文件被真實的UID所有
-R 文件或目錄可以被真實的UID/GID讀取
-S 為socket(套接字)
-T 是否為文本文件
-W 文件或目錄可以被真實的UID/GID寫入
-X 文件或目錄可以被真實的UID/GID執行
-b 為block-special (特殊塊)文件(如掛載磁盤)
-c 為character-special (特殊字符)文件(如I/O 設備)
-d 為目錄
-e 文件或目錄名存在
-f 為普通文件
-g 文件或目錄具有setgid屬性
-k 文件或目錄設置了sticky位
-l 為符號鏈接
-o 文件被有效UID所有
-p 文件是命名管道(FIFO)
-r 文件可以被有效的UID/GID讀取
-s 文件或目錄存在且不為0(返回字節數)
-t 文件句柄為TTY(系統函數isatty()的返回結果;不能對文件名使用這個測試)
-u 文件或目錄具有setuid屬性
-w 文件可以被有效的UID/GID寫入
-x 文件可以被有效的UID/GID執行
-z 文件存在,大小為0(目錄恆為false),即是否為空文件,

註:以上參考了
Tutorialspoint, Perl - File I/O