Download presentation
Presentation is loading. Please wait.
1
張智星 (Roger Jang) jang@mirlab.org http://mirlab.org/jang 清大資工系 多媒體檢索實驗室
MATLAB 程式設計入門篇 檔案讀寫 張智星 (Roger Jang) 清大資工系 多媒體檢索實驗室
2
本章重點 很多計算工作的第一步就要是讀取資料 MATLAB 內建許多有關檔案讀寫的函數,可對二進制檔案或 ASCII 檔案進行下列處理:
開啟 關閉 儲存
3
高階的檔案讀寫指令(1/2) 先列出常用讀寫檔案指令,稍後將介紹用法 類別 支援檔案格式 指令 一般資料
MAT - MATLAB workspace load, save CSV - Comma separated numbers csvread, csvwrite DAT - Formatted text Importdata DLM - Delimited text dlmread, dlmwrite TAB - Tab separated text 試算表 XLS - Excel worksheet Xlsread WK1 - Lotus 123 worksheet wk1read, wk1write
4
高階的檔案讀寫指令(2/2) 類別 支援檔案格式 指令 科學資料
CDF - Common Data FormatFITS - Flexible cdfread, cdfwrite Image Transport System Fitsread HDF - Hierarchical Data Format hdfread, hdfwrite 電影 AVI - Movie aviread 影像 TIFF, PNG, HDF, BMP, JPEG, GIF, PCX, XWD, CUR, ICO, RAS, PBM, PGM, PPM imread, imwrite 音訊 AU, SND - NeXT/Sun sound auread, auwrite WAV - Microsoft Wave sound wavread, wavwrite
5
csvread 使用 csvread 指令來讀取 條件: Ex:csvread01.m 資料檔案是由逗號分開 只有包含數值資料
fprintf('data.csv 的內容:\n'); type data.csv % 列出 data.csv 的內容 A = csvread('data.csv') % 將 data.csv 的內容讀到矩陣 A
6
執行結果 csvread 會傳回一個數值矩陣 其中缺席的資料將以 0 填入。 data.csv 的內容: 1, 2, 3 4, 5
6, 7, 8, 9 A = csvread 會傳回一個數值矩陣 其中缺席的資料將以 0 填入。
7
dlmread 如果數值資料的分界符號(Delimiters)不是逗點,就不能使用 csvread 指令,而要改用 dlmread 指令
Ex:dlmread01.m fprintf('data.dlm 的內容:\n'); type data.dlm % 列出 data.dlm 的內容 A = dlmread(‘data.dlm’, ‘\t’) % 將 data.dlm 的內容讀到矩陣 A,資料是以定位鍵隔開,
8
執行結果 上例中data.dlm 的資料是以定位鍵(Tab)隔開,因此 dlmread 指令的第二個引數是 ‘\t’,以代表定位鍵
1 2 3 4 5 A = 上例中data.dlm 的資料是以定位鍵(Tab)隔開,因此 dlmread 指令的第二個引數是 ‘\t’,以代表定位鍵
9
textread 如果檔案資料包含數值及字串,我們就必須改用 textread 指令 Ex:textread01.m
fprintf('data.txt 的內容:\n'); type data.txt % 列出 data.txt 的內容 [name, hobby, age] = textread('data.txt', '%s%s%d')
10
執行結果 在上述範例中,data.txt 包含三個欄位(或是三直行的資料) textread 可在第二個引數指定資料型態
Timmy OnlineGames 13 Annie Chatrooms 10 Roger Tennis 41 name = 'Timmy‘ 'Annie' 'Roger' hobby = 'OnlineGames' 'Chatrooms' 'Tennis' age = 13 10 41 在上述範例中,data.txt 包含三個欄位(或是三直行的資料) textread 可在第二個引數指定資料型態 例如上例中 %s 代表字串,%d 代表整數 也同時將讀入的資料設定到不同的輸出引數 由於資料型態的不同,輸出引數也有不同的型態 以上述範例來說,name 和 hobby 都是字串異值陣列,而 age 則是數值陣列。
11
使用定位鍵來分隔欄位 上例中,我們利用空格來分隔欄位 如果欄位值本身也有空格 ? Ex:textread02.m
一般常見的作法,是使用定位鍵來分隔欄位 Ex:textread02.m fprintf('data2.txt 的內容:\n'); type data2.txt % 列出 data2.txt 的內容 [name, hobby, age] = textread('data2.txt', '%s%s%d', 'delimiter', '\t')
12
執行結果 結果與前一例相同 textread 指令中加上對分界字元(Delimiters)的定義,就可以讀出由定位鍵所分隔的資料檔案
若不指定時,預設為空白鍵
13
讀取文字檔 textread 也可以讀取一個文字檔,同時把檔案內的每一列文字變成字串異質陣列裡面的每一個元素 Ex:textread03.m
Contents = textread('textread03.m','%s','delimiter','\n','whitespace',''); class(contents) % 印出 contents 的資料類別 contents{1} % 列出 contents 第一列 contents{2} % 列出 contents 第二列
14
執行結果 上例使用 textread 讀入 textread03.m(也就是此範例檔案),並顯示此檔案的第一列和第二列。
ans = cell contents=textread('textread03.m','%s','delimiter','\n','whitespace',''); class(contents) % 印出 contents 的資料類別 上例使用 textread 讀入 textread03.m(也就是此範例檔案),並顯示此檔案的第一列和第二列。 textread 指令的用法還有很多,功能也很強大 在MATLAB下輸入「help textread」,可以得到完整的技術支援。
15
Fileread 若只是要簡單地將一個檔案的內容送到一個字串,可以使用 fileread 指令 Ex:範例16-6:fileread01.m
out = fileread(‘data2.txt’); class(out) size(out)
16
執行結果 ans = char 1 64 上例中,fileread 指令會將檔案 data2.txt 的內容送到字串變數 out
上例中,fileread 指令會將檔案 data2.txt 的內容送到字串變數 out class(out) 的值是 char ,顯示 out 的資料型態是字串 size(out) 顯示字串 out 的長度是 64。
17
影像與音訊檔案 有關於影像檔案的讀寫,請參閱本書第十九章「影像顯示與讀寫」;
有關音訊檔案的讀寫,請參閱本書第二十章「音訊讀寫、錄製與播放」。
18
更繁複的文字檔案格式 一般情況下 資料格式比較繁複時 盡量採取先前介紹的內建指令來進行讀寫,效率才會高。
需要一列一列讀進來,再進行剖析(Parsing) 相關指令將在以下介紹。
19
開啟檔案 無論讀寫 ASCII 或二進制檔案,都必需先用 fopen 函數來開啟檔案,語法如:
fid = fopen(filename, permission) 其中 filename 表示欲讀寫的檔案名稱 permission 則表示欲對檔案進行的處理方式,可以是下列任一字串: l ‘r’:只准讀取(reading)檔案 l ‘w’:只准寫入(writing)檔案 l ‘a’:只准加入(appending)檔案 l 'a+':可讀取及加入檔案(reading and appending) 省略第二個引數,permission 的預設值就是 ‘r’。
20
有關fopen 在windows下,permission 字串必需能夠分辨binary或 ASCII 檔案。
例如:若要讀binary檔案,則 permission 字串必需是“rb” fopen 另外支援很多 permission 字串,可輸入 「help fopen」 得到完整的資訊。 fopen 函數傳回一個檔案辨識碼(通常是個大於2的整數),我們可用此辨識碼來對此檔案進行各種讀寫的處理。
21
Ex:fopen01.m 上例可知當檔案不存在時,回傳的 fid 是 –1 同時 message 會包含相關的錯誤資訊。
[fid, message] = fopen('no_such_file', 'r'); fprintf('fid = %d\n', fid); fprintf('message = %s\n', message); fid = -1 message = Sorry. No help in figuring out the problem . . . 上例可知當檔案不存在時,回傳的 fid 是 –1 同時 message 會包含相關的錯誤資訊。
22
Ex:fopen02.m 若開啟成功,則傳回的 fid 是一個大於 2 的整數,而且傳回的 message 是一個空字串,例如:
[fid, message] = fopen('fopen02.m', 'r'); fprintf('fid = %d\n', fid); fprintf('message = %s\n', message); fid = 3 message =
23
提示 為了安全起見,最好在每次使用 fopen 時,都測試其傳回的 fid 是否為有效值。 輸出位置
MATLAB 使用 fid=1 來代表「標準輸出(Standard Output) fid=2 代表「標準錯誤輸出」(Standard Error) 若使用fid=1或2時,可不使用 fopen 來開啟檔案 Try this to see their difference: fprintf(1, 'This is standard output!\n'); fprintf(2, 'This is standard error!\n');
24
關閉檔案 完成檔案的讀寫之後,記得要使用 fclose 函數來關閉檔案,用法如下: 若一切順利,fclose 傳回 0。
status = fclose(fid); 若一切順利,fclose 傳回 0。 若無法順利關閉檔案,則 fclose 傳回 -1。 為避免因開啟檔案過多而造成系統資源浪費,一般在完成檔案的讀寫後,即應使用 fclose 來關閉檔案
25
提示 若要一次關閉所有開啟的檔案,可用 fclose('all') 或是 fclose all。
開啟及關閉檔案都是比較耗時的函數,因此盡量不要將他們置於迴圈之中,以提高程式執行效率。
26
讀取 ASCII 檔案(1/2) fgetl 函數: 可將 ASCII 檔案的內容中的某一列讀出
Ex:fgetl01.m fid = fopen('mean.m', 'r'); while feof(fid)==0 % feof 測試檔案指標是否已到達結束位置 line = fgetl(fid); disp(line); end
27
讀取 ASCII 檔案(2/2) 執行上述程式後,MATLAB 會… fgets 和 fgetl 均可由檔案讀取一列資料:
先在目前目錄找尋 mean.m 若找不到,再根據搜尋路徑,找出 mean.m 指令的位置然後再將其內容一列一列地列出。 輸入「which mean」可顯示檔案所在的路徑 fgets 和 fgetl 均可由檔案讀取一列資料: fgetl 會取得一列,但不包含換列字元 fgets 則保留換列字元
28
應用:模擬unix的grep指令 grep :用來找出包含某一特定字串的一列
function grep(filename, pattern) fid = fopen(filename, 'r'); line_number = 0; while feof(fid) == 0, line = fgetl(fid); matched = findstr(line, pattern); if ~isempty (matched) fprintf('%d: %s \n', line_number,line); end line_number = line_number + 1; fclose(fid);
29
執行結果 如欲列出 grep.m 中包含 'matched' 字串的每一列,可輸入如下:
>> grep('grep.m', 'matched') 6: matched = findstr(line, pattern); 7: if ~isempty (matched) 若要進行更複雜的字串比對,請參考本書姊妹作「MATLAB 程式設計:進階篇」中的第四章「通用運算式」。 例如要在一個檔案中找出「b 和 d 中間夾1至3個母音」的英文字
30
fscanf 函數fscanf可對ascii檔案作更精確的讀取,用法如下: matrix = fscanf(fid, format)
format 是格式指定字串(Format Specifier) 常用的格式指定字串有下列幾種: %s:字串 %d:10進位的整數 %g:雙倍精準(Double-precision)的浮點數 其他各種格式指定字串可輸入 help fscanf 來得到詳細的說明
31
Ex:fscanf01.m 有一文字檔 test.txt 如下: 1 4 9 16 25 36 49 64 81 100
fid = fopen('test.txt', 'r'); myData = fscanf(fid, '%g'); fclose(fid); myData % 顯示 myData
32
執行結果 上例顯示了 MATLAB 的 fscanf 指令和 C 的 fscanf 指令的最大不同:
myData = 1 4 9 16 25 36 49 64 81 100 上例顯示了 MATLAB 的 fscanf 指令和 C 的 fscanf 指令的最大不同: MATLAB 的 fscanf 指令是向量化的(Vectorized) 只要讀入資料的型態正確,MATLAB 的 fscanf 指令會一再執行 同時把所得結果存放於一個向量並回傳。
33
sscanf sscanf 函數和 fscanf 的功能很類似 sscanf 函數從字串(Strings)中讀取資料
ex:sscanf01.m str = num2str([pi, sqrt(2), log10(3)]) %建立一字串str retrieved = sscanf(str, '%g') %擷取str中的double str = retrieved = 3.1416 1.4142 0.4771
34
寫入 ASCII 檔案 fprintf 函數可將資料依格式指定字串來寫入 ASCII 檔案,其使用語法如下:
fprintf(fid, format, y) 其中 fid 是欲寫入之檔案的辨識碼 format 是格式指定字串,用以指定資料寫至檔案的格式 y 是 MATLAB 的資料變數 常用的格式指定字串有下列幾種: %e:科學記號,即將數值表示成 a×10b 的形式 %f:固定欄寬(含整數與小數部份)的表示法 %g:自動選取 %e 或 %f 其他各種格式指定字串可輸入 help fprintf 來得到詳細的線上說明。
35
應用:將平方根表寫入檔案 Ex:fprintf01.m x = 1:10; y = [x; sqrt(x)];
fid = fopen('squareRootTable.txt', 'w'); fprintf(fid, 'Table of square root:\r\n'); fprintf(fid, '%2.0f => %10.6f\r\n', y); fclose(fid); dos('start squareRootTable.txt'); % 開啟 squareRootTable.txt
36
執行結果 在上例中… %2.0f 印出的總欄寬為 2,且不帶小數 %10.6f 印出的總欄寬為 10,包含 6位的小數
請自行試驗後開啟 squareRootTable.txt 來驗證 squareRootTable.txt
37
sprintf sprintf 函數和 fprintf 函數的功能很類似 sprintf 將資料以字串形式傳回 Ex:
>> str = sprintf('log(%f) = %e\n', 2, log(2)) str = log( ) = e-001
38
暫存目錄 某些應用需要用到暫存目錄及暫存檔案。(例如:產生一個html檔案,再使用瀏覽器開啟。)
欲取用系統的暫存目錄,可用 tempdir如下: >> directory = tempdir Result: directory = C:\Users\jang\AppData\Local\Temp\
39
暫存檔案 欲開啟一暫存檔案,可用 tempname,如下: >> filename = tempname Result:
filename = C:\Users\jang\AppData\Local\Temp\tpda998b2b_cb6f_4b68_9814_6dbab1d44abd
40
提示 上述範例是在 Windows 7 進行測試 不同系統下tempdir 和 tempname會依作業系統的環境變數而產生不同的回傳字串
’C:\windows\temp\’ tempname 傳回的字串可能是 ’C:\WINDOWS\TEMP\tp512124’。
41
應用:產生暫存的 HTML 檔案 以下利用 tempname 產生一個暫存的 HTML 檔案,然後再將此檔案顯示在瀏覽器。
Ex: writeHTML.m filename = [tempname, '.html']; fid = fopen(filename, 'w'); fprintf(fid, '<html><body>\n'); fprintf(fid, 'This is a test homepage written by MATLAB!\n'); fprintf(fid, '</body></html>'); fclose(fid); dos(['start ', filename]); % 啟動和 .html 相連結的應用程式
42
執行結果 上例產生之網頁如下: 當MATLAB 的計算結果可用列表(Table)或多媒體檔案(如影像、聲音、動畫等)來呈現時,由網頁來顯示這些結果是不錯的選擇。
43
網路檔案的讀取 MATLAB 也可以直接讀取網路上的檔案
通常我們是採用 URL(Universal Resource Locator)的方式來指定這些網路上的檔案: 一般網頁: FTP ftp://ftp.mathworks.com/pub/pentium/Moler_1.txt 本機硬碟檔案: file:///C:\winnt\matlab.ini
44
urlread Ex: urlread01.m contents = urlread(' disp(contents); 上例中使用 urlread 指令來讀取筆者在清華大學資訊系的首頁,同時將結果指定到字串變數 contents
45
執行結果 <HTML> <HEAD> <META http-equiv="Refresh"
content="0; URL= </HEAD> <BODY> The link you just clicked is obsolete.<br> You are being transported automatically to Roger Jang's current homepage at <a href=" </BODY> </HTML>
46
urlwrite 指令(1/2) urlwrite指令可以直接在讀取網頁後,就儲存到本機硬碟中 Ex:urlread02.m
tempFile = [tempname, '.html']; % 指定暫存檔案 urlwrite(' tempFile); % 將網頁內容寫到檔案 dos(['start ', tempFile]); % 開啟此檔案
47
urlwrite 指令(2/2) 在上例中,我們將 的網頁內容寫到一個暫存檔案,然後再使用瀏覽器開啟此檔案。 另一個和網路相關的功能 – sendmail 可用來寄發電子郵件 雖然這個功能和檔案讀寫沒有直接關係,但也在此一併說明。
48
sendmail 指令 sendmail 指令的用法: sendmail(to, subject, message, attachment)
若是只有一位收件者,可用字串表示 若是有多位收件者,可以使用字串異質陣列來表示。 subject:主題,以字串表示。 message:電子郵件的內容,以字串表示。 attachment:附加檔案,用異質陣列來表示。
49
Ex:sendmail01.m 請將 to 的內容改為你自己本身的電子郵件,並試著執行一次,以確認此程式碼的正確性。
to = subject = 'Test from a MATLAB program'; message = 'This is a test sent via sendmail.'; attachment = {'c:\windows\matlab.ini'}; sendmail(to, subject, message, attachment); 請將 to 的內容改為你自己本身的電子郵件,並試著執行一次,以確認此程式碼的正確性。
50
提示 可能還需要先使用setpref來設定smtp server及發信人等。(MATLAB 會有提示文字。)
根據筆者在 MATLAB 6.5 的測試,sendmail 目前還不支援中文。 而 MATLAB 7.0 對 sendmail 新增了一些新功,請輸入 help sendmail 來獲取最新的線上支援。 若要在郵件內容加入換列,可以使用 ASCII 碼「10」 例如:message=[’Sir:’, 10, ‘This is a test’]。
51
讀取二進制資料 用fread 函數可從檔案中讀取二進制資料 fread會將每一個位元組看成一個整數,並將結果以一矩陣傳回。
例如,檔案 test2.txt 的內容如下: This is a test!
52
Ex:fread01.m Result: This is a test! char 可將 myData 的整數轉成 ASCII 字元
fid = fopen('test2.txt', 'r'); myData = fread(fid); char(myData') % 驗證所讀入的資料是否正確 fclose(fid); Result: This is a test! char 可將 myData 的整數轉成 ASCII 字元 取 myData 的轉置是為了印出橫列,易於閱讀
53
Ex:fread02.m fread 函數可用第二個輸入引數來控制傳回矩陣的大小
fid = fopen('test2.txt', 'r'); myData = fread(fid, 4) % 只讀 4 個位元組 fclose(fid); myData = 84 104 105 115
54
Ex:fread03.m Result: 此時 myData 為 2X3 的矩陣。
fid = fopen('test2.txt', 'r'); myData = fread(fid, [2 3]) fclose(fid); Result: myData = 此時 myData 為 2X3 的矩陣。
55
Fread的第3個引數 控制 fread 在將二進制資料轉成 MATLAB 矩陣時所用的精確度 包含: 常用的精準度有下列幾種:
一次讀取的位元數(Number of Bits) 這些位元數所代表的資料型態 常用的精準度有下列幾種: char:帶符號的字元(8 bits) uchar:不帶符號的字元(8 bits) short:短整數(16 bits) int:整數(通常是 32 bits) long:長整數(32 或 64 bits) ushort:不帶符號的短整數(16 bits) uint:不帶符號的整數(32 bits) ulong:不帶符號的長整數(32 或 64 bits) float:單精準浮點數(32 bits) double:雙精準浮點數(64 bits)
56
Ex:fread04.m Result: myData = 26708 myData2 =
fid = fopen('test2.txt', 'r'); myData = fread(fid, 1, 'short') fclose(fid); myData2 = bin2dec([dec2bin(abs('h'),8), dec2bin(abs('T'),8)]) Result: myData = 26708 myData2 =
57
說明:fread04.m 上例將 text2.txt 以短整數的方式讀入 要注意的是: 也就是以 16 bit 為一個單位來轉換成整數
讀出來的第一個數字,會等於將 'h' 和 'T' 轉換成 8 bit,再並排成 16 bits 然後再轉換成十進位的整數值 要注意的是: 雖然原檔案的前兩個位元組是 'T' 和 'h',但是在以 16 bits 為一個單位時… 'T' 會是 LSB(Least Significant Bits) 而 'h' 則是 MSB(Most Significant Bits) 因此我們再重組成 16 bits 時,‘h’ 會在前而 ‘T’ 會在後 The byte order is Little Endian!
58
寫入二進制檔案 fwrite 函數: 以下用fwrite 產生一大小為 40 bytes 的二進制檔案
矩陣 -> 二進制格式 -> 寫入檔案 傳回成功寫入的個數。 以下用fwrite 產生一大小為 40 bytes 的二進制檔案 在使用 type 指令來顯示檔案內容時,看不到其內容 因為是 binary 檔案 如果 count 的值小於 10,就表示 fread 的運算有誤 Ex: fwrite01.m fid = fopen('test.bin', 'w'); count = fwrite(fid, randperm(10), 'int32'); fclose(fid); type test.bin
59
控制檔案位置指標 檔案位置指標: 決定下一次進行資料讀取或寫入的位置。 控制此指標的函數如下: feof 測試指標是否在檔案結束位置
fseek 設定指標位置 ftell 取得指標位置 frewind 重設指標至檔案起始位置
60
foef 測試指標是否在檔案結束位置 Ex:feof01.m 在上例中,feof(fid) 傳回 1,表示檔案指標已經在檔案結束位置
fid = fopen('test.txt'); A = fscanf(fid, '%g', [3 4]) feof(fid) 在上例中,feof(fid) 傳回 1,表示檔案指標已經在檔案結束位置 因為 test.txt 只包含 10 個數目字。
61
執行結果 A = ans = 1
62
frewind 從 test.txt 的起始位置讀出資料 >> frewind(fid);
>> A = fscanf(fid, '%g', 5) Result: A = 1 4 9 16 25
63
fseek 用於設定指標位置,其格式如下 status = fseek(fid, offset, origin) 其中 fid 是檔案識別碼
offset 是偏移量(以 byte 為單位,可以是正數或負數) origin 代表基準點,可包含下列字串: 'cof':指標的現在位置(Corrent position of File) 'bof':檔案的起始位置(Beginning of File) 'eof':檔案的結束位置(End of File)
64
ftell 傳回現在的指標位置 Ex:ftell01.m 40 代表指標已在檔案結束位置。
fid = fopen('test.bin', 'w'); count = fwrite(fid, randperm(10), 'int32'); ftell(fid) ans = 40 40 代表指標已在檔案結束位置。
65
再移動一次指標位置 欲將指標向前移動 10 bytes,可輸入如下: >> fseek(fid, -10, 'cof');
>> ftell(fid) Result: ans = 30 此代表指標的新位置是 30。
66
本章指令彙整 高階的文字檔案讀寫 開檔/關檔 csvread/csvwrite dlmreadd/lmwrite textread
讀寫以逗點分界欄位的數值資料檔案 dlmreadd/lmwrite 讀寫以特定字元來當分界欄位的數值資料檔案 textread 讀入固定欄位的文字資料檔 開檔/關檔 fopen 開啟檔案 fclose 關閉檔案
67
本章指令彙整(cont) 二進制資料 格式化資料 fread fwrite fscanf fprintf fgetl fgets
從檔案讀取二進制資料 fwrite 將二進制資料寫入檔案 格式化資料 fscanf 從檔案讀取格式化資料 fprintf 將格式化資料寫入檔案 fgetl 從檔案讀取一列資料,但捨去換行字元 fgets 從檔案讀取一列資料,但保留換行字元
68
本章指令彙整(cont) 字串 檔案位置控制 sprintf sscanf ferror feof fseek 將格式化資料寫至字串
從字串讀取格式化資料 檔案位置控制 ferror 檔案輸入/輸出的錯誤狀態 feof 測試是否已到檔案結束位置 fseek 設定檔案定位器
69
本章指令彙整(cont) 暫存檔案/目錄 ftell frewind tempdir tempname 讀取檔案定位器 回轉檔案定位器
取得暫存目錄的名字 tempname 取得暫存檔案的名字
Similar presentations