660 likes | 843 Vues
檔案讀寫. 方煒 台大生機系. 本章重點. MATLAB 內建許多有關檔案讀寫的函數 對二進制檔案或 ASCII 檔案都可以進行處理 開啟 關閉 儲存. 高階的檔案讀寫指令. 先列出常用讀寫檔案指令,稍後將介紹用法. 高階的檔案讀寫指令( cont). csvread. 使用 csvread 指令來讀取 條件: 資料檔案是由 逗號 分開 只有包含數值資料 Ex:csvread01.m. fprintf('data.csv 的內容: n'); type data.csv % 列出 data.csv 的內容
E N D
檔案讀寫 方煒 台大生機系
本章重點 • MATLAB 內建許多有關檔案讀寫的函數 • 對二進制檔案或 ASCII 檔案都可以進行處理 • 開啟 • 關閉 • 儲存
高階的檔案讀寫指令 • 先列出常用讀寫檔案指令,稍後將介紹用法
csvread • 使用 csvread 指令來讀取 • 條件: • 資料檔案是由逗號分開 • 只有包含數值資料 • Ex:csvread01.m fprintf('data.csv 的內容:\n'); type data.csv % 列出 data.csv 的內容 A = csvread('data.csv') % 將 data.csv 的內容讀到矩陣 A
result data.csv 的內容: 1, 2, 3 4, 5 6, 7, 8, 9 A = 1 2 3 0 4 5 0 0 6 7 8 9 • csvread 會傳回一個數值矩陣 • 其中缺席的資料將以 0 填入。
dlmread • 如果數值資料的分界符號(Delimiters)不是逗點,就不能使用 csvread 指令,而要改用 dlmread 指令 • Ex:dlmread01.m fprintf('data.dlm 的內容:\n'); type data.dlm % 列出 data.dlm 的內容 A = dlmread('data.dlm', '\t') % 將 data.dlm 的內容讀到矩陣 A
Result data.dlm 的內容: 1 2 3 4 5 6 7 8 9 A = 1 2 3 0 4 5 0 0 6 7 8 9 • 上例中data.dlm 的資料是以定位鍵(Tab)隔開,因此 dlmread 指令的第二個引數是 ‘\t’,以代表定位鍵
textread • 如果檔案資料包含數值及字串,我們就必須改用 textread 指令 • Ex:textread01.m fprintf('data.txt 的內容:\n'); type data.txt % 列出 data.txt 的內容 [name, hobby, age] = textread('data.txt', '%s%s%d')
result data.txt 的內容: 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 則是數值陣列。
使用定位鍵來分隔欄位 • 上例中,我們利用空格來分隔欄位 • 如果欄位值本身也有空格 ? • 改用定位鍵來分隔欄位 • Ex:textread02.m fprintf('data2.txt 的內容:\n'); type data2.txt % 列出 data2.txt 的內容 [name, hobby, age] = textread('data2.txt', '%s%s%d', 'delimiter', '\t')
result • 結果與前一例相同 • textread 指令中加上對分界字元(Delimiters)的定義,就可以讀出由定位鍵所分隔的資料檔案 • 若不指定時,預設為空白鍵
讀取文字檔 • textread 也可以讀取一個文字檔 • 同時把檔案內的每一列文字變成字串異質陣列裡面的每一個元素 • Ex:textread03.m Contents = textread('textread03.m','%s','delimiter','\n','whitespace',''); class(contents) % 印出 contents 的資料類別 contents{1} % 列出 contents 第一列 contents{2} % 列出 contents 第二列
Result ans = cell ans = contents=textread('textread03.m','%s','delimiter','\n','whitespace',''); ans = class(contents) % 印出 contents 的資料類別 • 上例使用 textread 讀入 textread03.m(也就是此範例檔案),並顯示此檔案的第一列和第二列。 • textread 指令的用法還有很多,功能也很強大 • 在MATLAB下輸入「help textread」 • 可以得到完整的技術支援。
Fileread • 若只是要將一個檔案的內容送到一個字串,可以使用 fileread 指令 • Ex:範例16-6:fileread01.m out = fileread(‘data2.txt’); class(out) size(out)
Result ans = char ans = 1 64 • 上例中,fileread 指令會將檔案 data2.txt 的內容送到字串變數 out • class(out) 的值是 char ,顯示 out 的資料型態是字串 • size(out) 顯示字串 out 的長度是 64。
更繁複的檔案格式 • 一般情況下 • 盡量採取先前介紹的指令來進行讀寫。 • 資料格式比較繁複時 • 需要一列一列讀進來 • 再進行剖析(Parsing) • 相關指令將在以下介紹。
開啟檔案 • 無論讀寫 ASCII 或二進制檔案,都必需先用 fopen 函數來開啟檔案,語法如: • fid = fopen(filename, permission) • 其中 filename 表示欲讀寫的檔案名稱 • permission 則表示欲對檔案進行的處理方式,可以是下列任一字串: • ‘r’:只准讀取(reading)檔案 • ‘w’:只准寫入(writing)檔案 • ‘a’:只准加入(appending)檔案 • 'a+':可讀取及加入檔案(reading and appending) • 省略第二個引數,permission 的預設值就是 ‘r’。
有關fopen • 在windows下,permission 字串必需能夠分辨binary或 ASCII 檔案。 • 例如:若要讀binary檔案,則 permission 字串必需是“rb” • fopen 另外支援很多 permission 字串,可輸入 「help fopen」 得到完整的資訊。 • fopen 函數傳回一個檔案辨識碼,通常是個非負的整數,我們可用此辨識碼來對此檔案進行各種讀寫的處理。
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 . . .
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 =
Tips: • fopen 可傳回第二個引數來顯示錯誤訊息。 • 為了安全起見,最好在每次使用 fopen 時,都測試其傳回的 fid 是否為有效值。 • MATLAB 使用 fid=1 來代表「標準輸出(Standard Output) • fid=2 代表「標準錯誤輸出」(Standard Error) • 因此在使用這兩個 fid 的值時,可以不必使用 fopen 來開啟檔案。
關閉檔案 • 完成檔案的讀寫之後,可用 fclose 函數來關閉檔案,用法如下: • status = fclose(fid); • 若一切順利,fclose 傳回 0。 • 若無法順利關閉檔案,則 fclose 傳回 -1。 • 為避免因開啟檔案過多而造成系統資源浪費,一般在完成檔案的讀寫後,即應使用 fclose 來關閉檔案
Tips: • 若要一次關閉所有開啟的檔案,可用 fclose('all') 或是 fclose all。 • 開啟及關閉檔案都是比較耗時的函數,因此盡量不要將他們置於迴圈之中,以提高程式執行效率。
讀取 ASCII 檔案 • fgetl 函數: • 可將 ASCII 檔案的內容中的某一列讀出 • 並將該列的 ASCII 內容以轉成字串傳回。 • Ex:fgetl01.m fid = fopen('mean.m', 'r'); while feof(fid)==0 % feof 測試檔案指標是否已到達結束位置 line = fgetl(fid); disp(line); end
讀取 ASCII 檔案(cont) • 執行上述程式後,MATLAB 會… • 先在目前目錄找尋 mean.m • 若找不到,再根據搜尋路徑,找出 mean.m 指令的位置然後再將其內容一列一列地列出。 • 輸入「which mean」可顯示檔案所在的路徑 • fgets 和 fgetl 均可由檔案讀取一列資料: • fgetl 會捨去換行字元 • fgets 函數則保留換行字元
應用:模擬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; end fclose(fid);
result • 如欲列出 grep.m 中包含 'matched' 字串的每一列,可輸入如下: >> grep('grep.m', 'matched') matched = findstr(line, pattern); if ~isempty (matched)
fscanf • 函數fscanf可對ascii檔案作更精確的讀取,用法如下: • matrix = fscanf(fid, format) • 其中 fid 是欲讀取之檔案的辨識碼 • format 是格式指定字串(Format Specifier) • 常用的格式指定字串有下列幾種: • %s:字串 • %d:10進位的整數 • %g:雙倍精準(Double-precision)的浮點數(Floating-point Numbers) • 其他各種格式指定字串可輸入 help fscanf 來得到詳細的說明
Ex: fscanf01.m • 有一文字檔 test.txt 如下: myData = 1 4 9 16 25 36 49 64 81 100 1 4 9 16 25 36 49 64 81 100 • 欲使用 fscanf 指令讀取其內容,可輸入如下: • fid = fopen('test.txt', 'r'); • myData = fscanf(fid, '%g'); • fclose(fid); • myData % 顯示 myData
Ex: sscanf • sscanf 函數和 fscanf 的功能很類似 • sscanf 函數從字串(strings)中讀取資料 • ex:sscanf.m str = num2str([pi, sqrt(2), log10(3)]) %建立一字串str retrieved = sscanf(str, ‘%g’) %擷取str中的double str = 3.1416 1.4142 0.47712 retrieved = 3.1416 1.4142 0.4771
寫入 ASCII 檔案 • fprintf 函數可將資料依格式指定字串來寫入 ASCII 檔案,其使用語法如下: • fprintf(fid, format, y) • 其中 fid 是欲寫入之檔案的辨識碼 • format 是格式指定字串,用以指定資料寫至檔案的格式 • y 是 MATLAB 的資料變數 • 常用的格式指定字串有下列幾種: • %e:科學記號,即將數值表示成 a×10b 的形式 • %f:固定欄寬(含整數與小數部份)的表示法 • %g:自動選取 %e 或 %f • 其他各種格式指定字串可輸入 help fprintf 來得到詳細的線上說明。
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
Result • 在上例中… • %2.0f 印出的總欄寬為 2,且不帶小數 • %10.6f 印出的總欄寬為 10,包含 6位的小數 • typesquareRootTable.txt 來看結果
sprintf • sprintf 函數和 fprintf 函數的功能很類似 • sprintf 將資料以字串形式傳回 • Ex: >> str = sprintf('log(%f) = %e\n', 2, log(2)) str = log(2.000000) = 6.931472e-001
暫存目錄 • 在某些應用上,可能需要用到暫存目錄及暫存檔案。 • 欲取用系統的暫存目錄,可用 tempdir如下: >> directory = tempdir • Result: directory = C:\DOCUME~1\jang\LOCALS~1\Temp\
暫存檔案 • 欲開啟一暫存檔案,可用 tempname,如下: >> filename = tempname • Result: filename = C:\DOCUME~1\jang\LOCALS~1\Temp\tp273132
Tips • 不同系統下tempdir 和 tempname會依作業系統的環境變數而產生不同的回傳字串 • 例如在 Windows 98 作業系統下 • tempdir 傳回的字串可能是 • ’C:\windows\temp\’ • tempname 傳回的字串可能是 • ’C:\WINDOWS\TEMP\tp512124’。
應用:產生暫存的 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 相連結的應用程式
Result • 上例產生之網頁如下: • 讓MATLAB 的計算結果可用列表(Table)或多媒體檔案(如影像、聲音、動畫等)來呈現時,由網頁來顯示這些結果是不錯的選擇。
網路檔案的讀取 • MATLAB 也可以直接讀取網路上的檔案 • 通常採用 URL(Universal Resource Locator)的方式來指定這些網路上的檔案: • 一般網頁: • http://www.mathworks.com • FTP • ftp://ftp.mathworks.com/pub/pentium/Moler_1.txt • 本機硬碟檔案: • file:///C:\winnt\matlab.ini
urlread • 上例中使用 urlread 指令來讀取筆者在台大生機系的首頁 • 同時disp(); 將結果指定到字串變數 contents • Ex: urlread01.m contents = urlread('http://ecaaser3.ecaa.ntu.edu.tw/cea/cea1.htm'); disp(contents);
urlwrite • urlwrite可以直接在讀取網頁後,就儲存到本機硬碟中 • Ex:urlread02.m tempFile = [tempname, '.html']; % 指定暫存檔案 urlwrite('http://www.google.com.tw', tempFile); % 將網頁內容寫到檔案 dos(['start ', tempFile]); % 開啟此檔案
Urlwrite(cont) • 在上例中,我們將 www.google.com.tw 的網頁內容寫到一個暫存檔案 • 然後再使用瀏覽器開啟此檔案。 • 另一個和網路相關的功能 –sendmail • 可用來寄發電子郵件 • 雖然這個功能和檔案讀寫沒有直接關係,但也在此一併說明。
sendmail • Sendmail 指令的用法: • sendmail(TO, SUBJECT, MESSAGE, ATTACHMENTS) • TO:收件者 • 若是只有一位收件者,可用字串表示 • 若是有多位收件者,可以使用字串異質陣列來表示。 • SUBJECT:主題,以字串表示。 • MESSAGE:電子郵件的內容,以字串表示。 • ATTACHMENTS:附加檔案,用異質陣列來表示。
Ex: sendmail01.m • 請將 to 的內容改為你自己本身的電子郵件,並試著執行一次,以確認此程式碼的正確性。 to = {'email1@aaa.bbb.ccc', 'email2@aaa.bbb.ccc'}; subject = 'Test email from a MATLAB program'; message = 'This is a test email sent via sendmail.'; attachment = {'c:\windows\matlab.ini'}; sendmail(to, subject, message, attachment);
Tips • MATLAB 6.5 的sendmail 不支援中文。 • MATLAB 7.0 對 sendmail 新增了一些新功能 • 請輸入 help sendmail 來獲取最新的線上支援。 • 若要在郵件內容加入換列,可以使用 ASCII 碼「10」 • 例如:message=[’Sir:’, 10, ‘This is a test’]。
讀取二進制資料 • 用fread 函數可從檔案中讀取二進制資料 • fread會將每一個位元組看成一個整數,並將結果以一矩陣傳回。 • 例如,檔案 test2.txt 的內容如下: This is a test!
Ex: fread01.m • Result: This is a test! • char 可將 myData 的整數轉成 ASCII 字元 • 取 myData 的轉制是為了使印出的效果易於閱讀 fid = fopen('test2.txt', 'r'); myData = fread(fid); char(myData') % 驗證所讀入的資料是否正確 fclose(fid);
Ex: fread02.m • fread 函數可用第二個輸入引數來控制傳回矩陣的大小 fid = fopen('test2.txt', 'r'); myData = fread(fid, 4) % 只讀 4 個位元組 fclose(fid); myData = 84 104 105 115