2010-06-17 32 views
6

在Perl中,使用字符串作爲包含8位數據的字節數組是合適的嗎?我可以在這個主題上找到的所有文檔都集中在7位字符串上。在Perl中,我可以將字符串視爲字節數組嗎?

舉例來說,如果我讀一個二進制文件的一些數據到$data

my $data; 

open FILE, "<", $filepath; 
binmode FILE; 
read FILE $data 1024; 

,我想第一個字節出來,是substr($data,1,1)合適? (再次假設它是8位數據)

我來自一個主要是C背景,我習慣於將一個char指針傳遞給一個read()函數。我的問題可能是我不明白Perl中字符串的底層表示是什麼。

回答

6

read命令,這裏轉載捆綁的文檔,提供了大量的信息,是有關你的問題。

read FILEHANDLE,SCALAR,LENGTH,OFFSET

read FILEHANDLE,SCALAR,LENGTH

嘗試讀取LENGTH 字符數據的到從指定變量FILEHANDLE SCALAR 。返回實際讀取的 個字符的數量,文件結束時爲0,如果 是錯誤(在後一種情況下也設置$!),則返回undef。將SCALAR 放大或縮小,以便實際讀取的最後一個字符是標量的最後一個字符 。

可以指定OFFSET將讀取的數據放在 以外的字符串中。負數OFFSET 指定放置在從字符串末尾向後倒數 的許多字符處。大於SCALAR長度的正偏移量會導致在讀取結果爲 之前,字符串被填充爲 所需的大小,其中「\ 0」字節爲 。

該調用實際上是通過Perl's或 系統的fread()調用實現的。要獲得真正的read(2)系統調用,請參閱 「sysread」。

注意字符:取決於文件句柄的狀態, 要麼讀取(8位)字節或字符。默認情況下,所有 文件句柄都以字節爲單位進行操作,但例如,如果文件句柄 已使用「:utf8」I/O層打開(請參閱「打開」,並打開 「open」雜注,open) O將使用UTF-8編碼的 Unicode字符,而不是字節。類似於「:編碼」 編譯指示:在這種情況下幾乎可以讀取任何字符。

+1

我的性質很迂腐,當我在文檔中讀到這個時,我發現'character'不明確。我不清楚它是指一個數據單元(即一個字節)還是一個字符串單元(取決於編碼) – Mike 2010-06-17 22:03:09

+4

調用'binmode FILE,':raw「或」binmod FILE「:bytes」'將始終無論您的默認IO層如何(例如,如果聲明「使用utf8」),以「字節」模式打開文件句柄。 – mob 2010-06-17 22:04:39

+0

我實際上同意使用「字符」對我來說就像是一個bug,尤其是考慮到「Encode(3perl)」中字符,字節和八位字節之間的區別。它恰好是合適的詞,但是如果它說「字符(由當前I/O層定義)」,我想我會喜歡它。我猜這也是對你的回答的批評,因爲'read'總是讀取「字符」 - 但有時「字符」被定義爲「八位字節」,有時被定義爲「UTF-8碼位」。 – darch 2012-10-31 16:01:54

1

如果要從二進制文件讀取字節,可能要使用sysopensysread。請參閱perlopentut

這是否合適或必要取決於您正在嘗試做什麼。

#!/usr/bin/perl -l 

use strict; use warnings; 
use autodie; 

use Fcntl; 

sysopen my $bin, 'test.png', O_RDONLY; 
sysread $bin, my $header, 4; 

print map { sprintf '%02x', ord($_) } split //, $header; 

輸出:

C:\Temp> t 
89504e47
0

如果你告訴我們你要用字節數組做什麼,它可能會幫助更多。處理二進制數據有多種方式,每種方法都適用於不同的工具集。

是否要將數據轉換爲Perl數組?如果是這樣,packunpack是一個好的開始。 split也可以派上用場。

是否要訪問字符串的單個元素而不拆開它?如果是這樣,substr是快速的,將爲8字節數據做伎倆。如果您需要其他位深度,請查看vec函數,該函數將字符串作爲位向量來執行。

是否要掃描字符串並將某些字節轉換爲其他字節?那麼s///tr///構造可能會有用。

0

請允許我發表一個關於將字符串視爲二進制數組的小例子 - 因爲我自己發現很難相信所謂的「substr」會處理空字節;但似乎它 - 下面是一個perl調試器終端會話的一個片段(與兩個串和陣列/列表辦法):

$ perl -d 

Loading DB routines from perl5db.pl version 1.32 
Editor support available. 

Enter h or `h h' for help, or `man perldebug' for more help. 

^D 
Debugged program terminated. Use q to quit or R to restart, 
    use o inhibit_exit to avoid stopping after program termination, 
    h q, h R or h o to get additional info. 

    DB<1> $str="\x00\x00\x84\x00" 

    DB<2> print $str 
� 
    DB<3> print unpack("H*",$str) # show content of $str as hex via `unpack` 
00008400 
    DB<4> $str2=substr($str,2,2) 

    DB<5> print unpack("H*",$str2) 
8400 
    DB<6> $str2=substr($str,1,3) 

    DB<7> print unpack("H*",$str2) 
008400 

[...] 

    DB<30> @stra=split('',$str); print @stra # convert string to array (by splitting at empty string) 
� 
    DB<31> print unpack("H*",$stra[3]) # print indiv. elems. of array as hex 
00 
    DB<32> print unpack("H*",$stra[2]) 
84 
    DB<33> print unpack("H*",$stra[1]) 
00 
    DB<34> print unpack("H*",$stra[0]) 
00 
    DB<35> print unpack("H*",join('',@stra[1..3])) # print only portion of array/list via indexes (using flipflop [two dots] operator) 
008400 
1

字符串是「字符」,這比一個字節大的字符串。 1你可以將字節存儲在它們中,並將它們作爲字符來操縱它們,其中包括substr等等,只要你只是操縱內存中的實體,一切都非常漂亮。數據存儲很奇怪,但這大多不是你的問題。 2

當您嘗試讀取和寫入文件時,您的字符可能無法映射到字節的事實變得重要和有趣。更不用說煩人了。這種煩惱實際上被Perl試圖在常見情況下做你想做的事情變得更糟:如果字符串中的所有字符都適合一個字節,並且恰好在非Windows操作系統上,那麼實際上並沒有做任何特殊的事情來讀寫字節。然而,Perl會抱怨,如果你已經存儲了一個非字節大小的字符,並試圖寫它,而不是給它一個關於如何處理它的線索。

這是一個有點遠的地方,很大程度上是因爲編碼是一個大而令人困惑的話題。讓我在此處留下一些參考資料:請看Encode(3perl)open(3perl),perldoc openperldoc binmode,以獲得許多熱鬧和血腥的細節。

所以總結答案是「是的,你可以把字符串視爲它們包含字節,如果它們確實包含字節的話,你可以通過只讀和寫字節來保證。」

1:或者是迂迴地「,它可以表示比字節更大的值範圍,儘管它們在方便時以字節存儲」。我認爲。

2:對於記錄來說,Perl中的字符串在內部由稱爲'PV'的數據結構表示,除了字符指針外,它還知道像字符串長度和當前值pos3

3:好吧,如果它開始有趣,它將開始存儲當前值pos。另見

use Devel::Peek; 

my $x = "bluh bluh bluh bluh"; 
Dump($x); 
$x =~ /bluh/mg; 
Dump($x); 
$x =~ /bluh/mg; 
Dump($x); 
相關問題