檔案輸入與輸出.

Slides:



Advertisements
Similar presentations
Linux 环境及 Shell 程序 操作系统实验 1. 二、 Shell 编程与进程通信 常用 shell 命令 文件及文件属性操作 ls 、 cp 、 mv 、 rm ln 、 ln –s 、 chmod 、 groupadd 、 useradd 输入输出操作 echo 、 cat >> 、
Advertisements

第一單元 建立java 程式.
計算機程式語言實習課.
行程(process).
Linux File System Li-Shien Chen.
第 5 章 文件I/O操作.
File Access 井民全製作.
Project 2 JMVC code tracing
Chapter 5 迴圈.
複習 struct score_Type{ int chinese,english; }; struct my_Type{
C File System.
计算概论 第二十一讲 文件操作 北京大学信息学院.
JAVA 程式設計與資料結構 第十二章 JAR File.
JAVA 程式設計與資料結構 第六章 輸出與輸入.
第七章. 文件系统 (lab5).
第7章 Linux环境编程.
客戶端的檔案上傳 HtmlInputFile檔案控制項 上傳單一檔案 同時上傳多個檔案.
第10章 文件操作.
4B冊 認識公倍數和最小公倍數 公倍數和最小公倍數的關係.
第10章 文件操作.
SQL Stored Procedure SQL 預存程序.
安裝JDK 安裝Eclipse Eclipse 中文化
2017 Operating Systems 作業系統實習 助教:陳主恩、林欣穎 實驗室:720A.
連結資料庫管理系統.
程式設計 博碩文化出版發行.
|13 檔案資料讀寫.
檔案與磁碟的基本介紹.
第二章 SPSS的使用 2.1 啟動SPSS系統 2.2 結束SPSS系統 2.3 資料分析之相關檔案 2.4 如何使用SPSS軟體.
作業系統實習課(四) -檔案管理- 實驗室:720A 助教:鄧執中.
第七章 檔案處理.
雲端計算.
私立南山高中 信息組 電腦研習 電腦資料的備份 中華民國 99年4月20日 星期二.
第10章 檔案與資料夾處理 10-1 檔案的基礎 10-2 文字檔案的讀寫 10-3 二進位檔案的讀寫 10-4 檔案與資料夾處理.
Linux 文件操作——系统调用和标准 IO 库
Chap3 Linked List 鏈結串列.
第一單元 建立java 程式.
Linux作業系統 電腦教室Linux使用說明.
安裝 / 操作 flashget SOP (以Win 7 作業系統為範例)
挑戰C++程式語言 ──第8章 進一步談字元與字串
SOCKET( ).
C標準輸出入函數庫 與 作業系統.
引用檔案.
C qsort.
File Input and Output Chap. 11: 施威銘的書 Chap. 7: K&R.
檔案輸入與輸出.
利用 EditorConfig 自訂文字編輯器設定
第二章 类型、对象、运算符和表达式.
挑戰C++程式語言 ──第7章 輸入與輸出.
Pthread.
陣列與結構.
第10章 檔案系統 (file system).
Unix 安裝過程 使用2個磁片 到 rawwrite bootnet.img drvnet.img 利用rawwrite 將image檔寫入磁片.
基本指令.
程式移植.
Chapter 15 檔案存取 LabVIEW中的檔案存取函數也可將程式中的資料儲存成Excel或Word檔。只要將欲存取的檔案路徑位址透過LabVIEW中的路徑元件告訴檔案存取函數後,LabVIEW便可將資料存成Excel或Word檔;當然也可以將Excel或Word檔的資料讀入LabVIEW的程式中。
2018 Operating Systems 作業系統實習 助教:林欣穎 實驗室:720A.
实验二:添加Linux系统调用及熟悉常见系统调用
MultiThread Introduction
Quiz1 繳交期限: 9/28(四).
作業一: 安裝Linux於btrfs上 中正大學 作業系統實驗室 指導教授:羅習五
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
作業系統實習課(二) -Scheduler-Related System Calls-
Array(陣列) Anny
Chapter 4 Multi-Threads (多執行緒).
Unix指令4-文字編輯與程式撰寫.
Develop and Build Drives by Visual C++ IDE
《操作系统设计与实现》 第5章 文件系统.
JUDGE GIRL 使用介紹 & 常見問題 TAs :
《操作系统设计与实现》 Linux系统编程.
Presentation transcript:

檔案輸入與輸出

檔案在Linux內是什麼樣子

檔案(file) 檔案是一堆數據的有序集合 對作業系統而言,可以由「目錄系統」找到一個檔案在硬碟上的 位置 對程式而言,必須先告訴作業系統,準備「使用」哪些檔案,作 業系統會「開啟」該檔案,並給該檔案一個代碼(file descriptor),隨後該程式使用該「代碼」操作該檔案

檔案(file) 對每一個行程,每一個開啟的檔案都會有一個檔案指標 檔案指標代表目前正在對「該位置」做操作 read、write、lseek會改變檔案指標的位置 檔案指標 檔案

檔案(file) 對每一個行程,每一個開啟的檔案都會有一個檔案指標 檔案指標代表目前正在對「該位置」做操作 read、write、lseek會改變檔案指標的位置 檔案內部可能有空洞 這些空洞在邏輯意義上都是0 某些檔案系統不支援有空洞的檔案 檔案指標 檔案 空洞 空洞

為什麼檔案系統需要支援「空洞」 例如一間公司,員工編號共五碼,第1XXXX代表製造部、 2XXXX代表研發部、3XXXX代表行銷部 如果檔案系統支援「洞」,那麼可以直接使用員工編號當index, 而不需要擔心浪費磁碟空間的問題,如: 資料 洞 資料 洞 資料 洞 研發部 行銷部 製造部

用一個例子開始:mycp

mycp.c

一堆的#include <xxx.h> 問題 舉例 記得函數的名稱就好 如果忘記或者不知道include 某個.h檔案,編譯器會告訴你 某函數未定義 針對該函數使用man查詢他需 要include哪些 $man perror NAME perror - print a system error message SYNOPSIS #include <stdio.h> void perror(const char *s);

mycp.c

open int open(const char *pathname, int flags); open的傳回值是file descriptor(檔案描述子),在系統中從0開始編 號 如果前面的號碼有缺號,open會優先使用最小的號碼當file descriptor 如:系統已經使用了0, 2, 3, 4,當使用open再開啟一個檔案時,file descriptor會是「1」 一個行程能夠開啟的檔案是有限的 可以使用getrlimit()的RLIMIT_FSIZE查看 當回傳值為-1代表發生了錯誤,例如:超出RLIMIT_FSIZE

open int open(const char *pathname, int flags, mode_t mode) 當flags設定為O_CREAT時mode的意義如下 owner, group, others的權限 set-user-ID、set-group-ID及sticky bit 介紹檔案系統會再介紹權限的相關意義

open() open (argv [1], O_RDONLY); 第一個參數是“路徑名” 為了讀 為了寫 open (argv [1], O_RDONLY); 第一個參數是“路徑名” 第二個參數告訴OS開啟這個 檔案的目的是「只讀取」 open(argv[2], O_WRONLY | O_CREAT, S_IRUSR| S_IWUSR); 第一個參數是“路徑名” 第二個參數告訴OS這個檔案只用 來寫入(O_WRONLY),如果 檔案不存在,就建立檔案 (O_CREAT) 第三個參數代表新建立的檔案的 讀寫屬性(owner可讀寫)

自學open man 2 open 2代表系統裡面的第二本書, system call

open重要參數 int open(const char *pathname, int flags); O_APPEND O_TRUNC 每次都會將資料加到檔案的最尾巴,就算是多個行程同時寫入,也能保 證原子性(完整性)的加到最尾巴 O_TRUNC 將檔案大小歸為零,我們在設計存檔功能時,通常需要加上這個參數才 可以保證不會有舊資料 O_CLOEXEC 使用execve時自動關閉檔案(execve後面會介紹) 避免另外一個程序存取原程序所開啟的檔案

自我學習 先打開檔案,讀取後再儲存 int truncate(const char *path, off_t length); int ftruncate(int fd, off_t length);

mycp.c

read() ssize_t read(int fd, void *buf, size_t count); 會從fd所代表的檔案讀取「最多」count個byte到指標buf所指向的記憶體 當回傳值大於1,代表讀取了多少個byte 回傳值等於0代表讀到了EOF(檔案結尾) 回傳值-1,代表讀取發生了錯誤

write() ssize_t write(int fd, const void *buf, size_t count); 將buf指向的資料共count個byte,寫入fd所代表的檔案 傳回值代表總共寫入了多少個byte 當傳回值為-1,代表發生了錯誤

mycp.c

perror void perror(const char *s); 依照1. 依照errno印出訊息 2. 字串S 假設errno是1,perror(“the error is”)會印出「the error is: Operation not permitted」

什麼是errno errno是系統內的錯誤訊息代碼 如果呼叫一個C函數時發生了錯誤,則errno會被設定為該錯誤所 代表的號碼 所有errno對應的錯誤訊息在sys_errlist

mycp.c

close() int close(int fd); 使用完一個檔案,使用close告訴作業系統使用完畢 作業系統會依照當時的狀況(最後一個存取該檔案的行程),決 定是否釋放相關資源 成功回傳0,失敗回傳-1

如果忘記close() 程式執行結束時,作業系統會自 動幫忙關閉檔案 但如果程式會執行很久呢? daemon? 使用lsof查看到底哪些檔案還沒 關閉 重要參數-p PROCESS_ID

自我學習 原子性的讀取和寫入 ssize_t pread(int fd, void *buf, size_t count, off_t offset); ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);

小節 初步了解open、read、write,並用這幾個函數設計了簡單的cp open可以接很多參數,同學們應該主動學習

lseek & file holes

hole.c

lseek() off_t lseek(int fd, off_t offset, int whence); 將檔案fd的檔案指標移動到從whence起算,偏移offset的位置 傳統上UNIX支援的whence有三種選擇 SEEK_SET:絕對位置 SEEK_CUR:從現在位置起算 SEEK_END:從結束位置起算 傳回值為從檔案開始的偏移值 錯誤時: 在執行lseek前先將errno設定為0 檢查傳回值是否等於-1「並且」errno不為0

hole.c 因此hole.c會產生一個名為 myHole的檔案,在開始位置寫 入1,往後移動10000 byte在 寫入2,往後移動10000 byte 在寫入3 $ls myHole -lhs 12K -rw------- 1 shiwulo shiwulo 196K Jan 13 04:24 myHole /*檔案大小為196K,佔據磁碟空間12K*/

使用mycp複製myhole $ ./mycp myHole myHole2 $ ls myH* -lhs 12K -rw------- 1 shiwulo shiwulo 196K Jan 13 04:24 myHole 196K -rw------- 1 shiwulo shiwulo 196K Jan 13 04:31 myHole2 /*檔案大小都是196K,但是myHole2佔據磁碟空間196K而非12K*/ $cmp myHole myHole2 /*使用cmp比較二者無差異*/

myHole內部構造 10000個0 10000個0 1 0000…0000 2 3

進階版的mycp.c,mycp2.c(第一部分) 一開始要宣告_GNU_SOURCE才可以使用進階版的lseek()

man lseek

SEEK_HOLE & SEEK_DATA 在新版的UNIX提供這二個新的選項,但必須手動打開,即 #define _GNU_SOURCE 洞的最前面 資料的最前面 1 0000…0000 2 3

進階版的mycp.c,mycp2.c(第二部分) 取得每個資料區段的位置及大小 移動到該區段的開頭位置 進行該區段的複製

結果 $./mycp myHole myHole2 $ ./mycp2 myHole myHole3 $ ls myH* -lhs 12K -rw------- 1 shiwulo shiwulo 196K Jan 13 04:24 myHole 196K -rw------- 1 shiwulo shiwulo 196K Jan 13 05:08 myHole2 12K -rw------- 1 shiwulo shiwulo 196K Jan 13 05:09 myHole3

小節 對於Linux及大多數的UNIX而言,「洞」並不會佔據空間 讀取「洞」,裡面的值都是0,因此第一個版本的cp會讓「洞」 佔據空間 使用Linux的系統擴充,SEEK_DATA及SEEK_DATA可以找出 洞,複製時可以跳過這些洞

協調式鎖定檔案flock

lock.c

執行結果 $ ./lock myHole e fd = 3 is opened end 先執行 後執行 $ ./lock myHole e fd = 3 is opened end $ ./lock myHole e fd = 3 is opened /*被鎖住了,除非另外一個行程unlock或者結束*/

flock() int flock(int fd, int operation); LOCK_SH:分享鎖,除了互斥鎖,可以多個人同時編譯 LOCK_EX:互斥鎖,只可以這個行程進行編譯 LOCK_UN:解開這個鎖 請注意,如果另外一個行程並未使用flock,那麼另一個行程就不需要遵照這些「鎖」

強制鎖

強制鎖(不建議使用) 在Solaris, HP-UX, and Linux上可以使用set-grup-id,讓一個檔 案只可以由一個行程開啟 具體的做法是在chmod前加上2,例如: chmod 2644 test

確保寫入 sync & fsync & fdatasync

三個類似的函數 void sync(void); int fsync(int fd); int fdatasync(int fd); 將所有的資料(包含meta-data)寫回磁碟 int fsync(int fd); 將fd代表的檔案的所有的資料(包含meta-data)寫回磁碟 int fdatasync(int fd); 將fd代表的檔案的所有的資料(「不」包含meta-data)寫回 磁碟

sync.c int main() { int fd; int num; fd = open("./hello1",O_WRONLY | O_CREAT, 0644); for(num=0; num <=100000; num++) { write(fd, "1234", sizeof("1234")); fsync(fd); if (num%10000==1) { write(1, "*", sizeof("*")); fsync(1); } return 0;

datasync.c int main() { int fd; int num; fd = open("./hello3",O_WRONLY | O_CREAT, 0644); for(num=0; num <=100000; num++) { write(fd, "1234", sizeof("1234")); fdatasync(fd); if (num%10000==1) { write(1, "*", sizeof("*")); fsync(1); } return 0;

nsync.c int main() { int fd; int num; fd = open("./hello2",O_WRONLY | O_CREAT, 0644); for(num=0; num <=100000; num++) { write(fd, "1234", sizeof("1234")); if (num%10000==1) { write(1, "*", sizeof("*")); fsync(1); } return 0;

sync.c的執行結果 $ time ./sync ********** real 0m21.215s user 0m0.136s sys 0m5.272s

比較 sync fdatasync no sync real 0m21.215s 0m17.545s 0m0.076s user sys 0m5.272s 0m3.980s 0m0.068s

小結 當多個程式讀取檔案時,可以用flock上鎖,但先決條件是所有的 程式在讀取之前都先使用flock 檔案的寫入會變更檔案的屬性,此外檔案內容的變化是否先暫存 在記憶體(buffer)呢。「同步更新」的東西越多,速度越慢, 但也越安全(例如系統突然斷電)

作業 設計一個程式,允許多名助教同時輸入成績 執行檔名稱addGrade 學號 成績,所有的成績都刊登在grade檔 案內,必須按照學號排序