檔案資料IO 的細節分析

2021-10-22 05:50:24 字數 2753 閱讀 9179

參考:

linux裝置驅動開發詳解:基於最新的linux4.0核心:宋寶華編著.

程式設計離不開資料, 所以資料獲取是程式設計的第一步.

資料io可以是阻塞式式的或非阻塞式的.  

例如讀取資料,當資料沒有準備好時,是把讀取執行緒或程序阻塞,還是立即返回乙個無資料的錯誤. 這可由使用者選擇.

預設的檔案開啟方式是阻塞式讀寫. 如果想非阻塞式讀寫,需要如此開啟檔案:

int fd = open(path,o_rdonly | o_nonblock)  

這個path 可能是個裝置檔案,例如:/dev/globalfifo  

這個open操作將會呼叫到驅動中的globalfifo_open(struct inode *inode, struct file *filp);

開啟的屬性(o_rdonly | o_nonblock) 會保留在filp->f_flags中

filp 是系統提供的乙個檔案結構指標, 開啟操作只需要把你的私有資料掛到filp->private_data

filp->private_data = globalfifo_devp;

inode 對應乙個檔案節點,這裡沒有用到,先不管它.

例如:read(fd,buf,5);

將會呼叫到驅動的read 函式

ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)

傳來的引數包括那個特定的filp 指標, 從這可以拿到源資料資訊.

還有使用者空間的位址和大小. 向這個地方copy

最後1個引數ppos, 是位置偏移指標, 從這裡(*ppos)=offset 可以拿到位址偏移.

所以當使用者讀走了count 個資料,為了保證下次繼續讀新資料,你需要把偏移更正一下.

*ppos += count;

seek 函式能夠直接改變檔案的讀寫指標, 他是如何使用的?

off_t lseek(int fd, off_t offset, int whence);

對應於驅動的

static loff_t globalfifo_llseek(struct file *filp, loff_t offset, int orig)

這個偏移值offset, 會被儲存到filp->pos 處

從開始處偏移 filp->f_pos = (unsigned int)offset; 或者從現在處偏移

filp->f_pos += offset;

這樣使用者讀取時能被正確的傳遞偏移

驅動中的讀函式,當資料不可讀時,如果是o_nonblock 模式,應立即返回

while (dev->current_len == 0) 

}

否則需要掛起執行的程序,當資源可用時再喚醒.

掛起很簡單,呼叫

__set_current_state(task_interruptible); //也允許訊號喚醒

schedule();

即可.如何喚醒?  這需要把當前程序加到乙個等待佇列中

declare_waitqueue(wait, current);

add_wait_queue(&dev->r_wait, &wait);

當有資料寫入時,喚醒這個等待佇列

wake_up_interruptible(&dev->r_wait);

我們都知道著名的select 函式

select(fd + 1, &rfds, &wfds, null, null);

它能同時監視讀,寫描述符集, 有乙個有效即被喚醒. 它是如何實現的?

原來select 函式會呼叫驅動的poll 函式,每乙個監控的fd的poll都會呼叫.

static unsigned int globalfifo_poll(struct file *filp, poll_table * wait)

它傳來乙個poll_table* wait, 應該有程序的資訊.

poll_wait(filp, &dev->r_wait, wait);

poll_wait(filp, &dev->w_wait, wait);

驅動把這個wait 加入到等待佇列中, 以後如果資源可用時,會喚醒這個等待佇列,從而

select 能夠從阻塞中繼續執行.

驅動的poll函式並不會阻塞,它加入等待佇列後,返回自己的狀態就可以了.

if (dev->current_len != 0)

if (dev->current_len != globalfifo_size)

return mask;

這會置位fdset 的對應bit, 使使用者知道哪個fd 置位了.

int fd = open("/dev/globalfifo", o_rdwr, s_irusr | s_iwusr); //開啟乙個檔案

signal(sigio, signalio_handler); //註冊乙個sigio 訊號處理器

fcntl(fd, f_setown, getpid()); // 設定本fd為非同步io, 第一步,設定current pid

int oflags = fcntl(fd, f_getfl);

fcntl(fd, f_setfl, oflags | fasync); // 設定為非同步標記

while (1)

當然,要支援非同步操作,驅動也要做相應修改. 主要是當資料可讀時,從驅動向呼叫者發sigio訊號

Java基礎 檔案資料IO操作

檔案資料io操作 1.1.字元流原理 reader是所有字元輸入流的父類而writer是所有字元輸出流的父類。字元流是以字元 char 為單位讀寫資料的。一次處理乙個unicode。字元流都是高階流,其底層都是依靠位元組流進行讀寫資料的,所以底層仍然是基於位元組讀寫資料的。1.2.常用方法 read...

Python資料分析筆記 檔案資料讀取

讀取檔案內容首行 path c users etisan desktop a.txt open path readline 注 檔案路徑要用雙反斜槓 第乙個 的作用是轉義字元 讀取檔案內容某一行 records line for line in open path records 1 匯入json,...

DBF檔案資料結構例項分析

dbf檔案資料結構例項分析下面以乙個具體例項來分析dbf資料結構 該 資料為 列1 列21 2 2 43 6 4 85 10 6 12 7 14 8 16 9 18 10 20 用ultraedit開啟該dbf檔案,其內容如下 現在先分解一下,找出檔案頭,並分析一下檔案頭的內容。首先看第乙個位元組,...