1. lseek函式
前兩次已經學過了write和read函式,這兩個函式在使用中可能存在對同乙個檔案多次操作的問題,因此不得不關注讀寫的起點是哪兒。假設有這麼乙個需求:乙個檔案中有6個字元,開啟檔案後我希望直接讀取第4個字元,這怎麼辦?顯然直接讀取是不行的了,你得移動讀寫起點。
lseek函式就是為這個需求而生的。
a)返回值為長整型,代表設定後的讀寫起點。是從檔案開頭開始算起的偏移位元組數,當為0時代表就是檔案開頭。顯然這個數字不應該小於0。一旦返回-1則代表執行函式出錯。
b)第乙個引數是檔案控制代碼
c)第二個引數是偏移量,它的含義取決於第三個引數。正數代表往後移動,負數代表往前移動。
d)第三個引數是偏移量的參考點。有三個取值
seek_set 讀寫偏移量以檔案開頭為參考
seek_cur 讀寫偏移量以當前所在位置為參考
seek_end 讀寫偏移量以檔案末尾為參考
e)讀和寫的起點是共用的,改變了讀的位置,意味著寫的位置也改了。
f)寫操作是覆蓋進行的。比如乙個檔案中原來有6個字元:abcdef,當移動游標到第四個位置,再寫入abc,會發現結果為abcdabc
2. 補充乙個知識點
我們把這種借助lseek函式,實現隨心所欲讀寫檔案任意位置的操作叫做隨機讀寫;那麼那種按部就班從頭開始讀寫的操作就叫做順序讀寫。
在linux中並非所有檔案都可以隨機讀寫,有不少檔案只能順序讀寫。那麼該怎麼判斷呢?
還是要借助lseek函式。像這樣呼叫:
offset=lseek(fd, 0, seek_cur);
因為偏移量寫著0,而參考起點是當前位置,那等於沒有移動。因此這個函式完完全全就是試探,如果返回值是-1,那說執行失敗。因此你操作的這個檔案不允許調整讀寫位置。
3. 所謂檔案的讀寫起點和檔案末尾到底指的是哪?
lseek函式涉及到很多偏移量、參考位置這樣的東西。看起來很簡單,卻很容易出現錯一位的情況,讓人十分撓頭。不如來個圖,把這些關係好好捋一捋,假設現在有乙個檔案,內容是「hello, welcome to linux world!」這個字串,一共有30個字元,但是檔案末尾會多出乙個轉義字元『/0』。因此檔案中一共有31個字元。
a)首先我們要明確一點,像下面這樣使用lseek函式可以計算出當前的讀寫位置(因為它以當前的讀寫位置為參考,無偏移,直接返回,那不就等於返回的就是當前的讀寫位置嘛)
lseek(fd, 0, seek_cur);
當我們第一次開啟檔案,立即執行上面的函式時,會發現結果是0而不是1。如果我們把讀寫位置理解成指向字元的箭頭,讀寫位置是幾,就代表指向的是第幾號字元。那麼對字元的標號,就必須是從0開始的!
按照這個約定,今後我說檔案的讀寫位置在9號位置時,其實我指的是實際意義上的第10個字元。反過來,如果我想讀取world這個字元時,我首先知道w是實際意義上的第25個字元,那麼它的標號其實是24,於是我只需要把讀寫位置調到24就行了。
注意:上述提到的幾號位,都是從檔案開頭開始算起的。如果從檔案末尾開始算起,顯然就是另一回事了。見下面的分解。
b)還是對例子中的檔案進行試驗,當我執行下面這個函式時:
lseek(fd, 0, seek_end);
返回值是31。從函式的引數配置上來解釋:以檔案末尾為起點,無偏移,直接返回讀寫位置。那麼就等於直接返回檔案末尾的讀寫位置咯。現在這個數值是31,代表實際意義上的第32個字元,但我們心理都清楚,其實檔案中只有31個字元。因此檔案末尾的讀寫位置,其實指的是最後乙個真實字元的後乙個byte位。
當然,像上面這樣呼叫函式,是可以用來計算檔案中到底有多少真實字元的,包括末尾的'\0'。
4. lseek函式使用體驗
a)先來個例子
假設現在我用lseek函式計算當前的讀寫位置,返回值是7。而我想讀取linux這5個字元,我該怎麼做?
三種思路:
其一,直接以檔案開頭為起點,調整讀寫位置。那麼我數一數,發現linux的首字母是實際意義上的第19個字元,那麼它的標號就是18。於是我就寫 lseek(fd, 18, seek_set);
其二,直接以檔案結尾為起點,調整讀寫位置。那麼我要確認這個位置從檔案末尾數過來,需要數到幾?
從上圖可以看出,要數13次。於是我就寫 lseek(fd, -13, seek_end);
其三,直接以當前的位置為起點,調整讀寫位置。那麼我要數一數,從當前位置數到目標位置,需要數到幾?
從上圖可以看出,要數11次。於是我就寫 lseek(fd, 11, seek_cur);
b)上述例子可以看出,要用好lseek函式,你得心理非常清楚seek_set、seek_cur和seek_end到底指向的是哪個字元(前面已經分析過)。同時你還必須非常清楚偏移量是多少,剛才的方法很原始,就是掰手指去數。
c)更多的時候,偏移量怎麼能靠自己去數,實在是太low了。
其一,也許我們知道兩個位置之間間隔了多少個字元。那麼偏移量就是間隔的字元數+1。
其二,也許我們知道兩個位置各自的標號。這個標號可能是從1開始也可能是從0開始。不過不重要,因為我們想知道的其實是二者之間的偏移。因此直接用二者的標號相減就行了。
5. 補充乙個知識吧
使用hexdump -c 檔名
可以把檔案中的資料以十六進製制的形式列印出來,比如上面例子中提到的檔案:
ps:這個檔案是我手打的,發現最後乙個位0a,對應換行符
6. ioctl函式
這個函式沒辦法深究,是因為它不具備共通性。
從教材上的描述可以看出來,這個函式有比較強的定製化色彩,主要應該針對裝置檔案的操作而言。這取決於驅動程式是怎麼寫的了。現在我暫時沒心思去研究某個具體的驅動怎麼寫,因此這個函式就先放一放。
Linux應用程式設計學習記錄(一)
今天學習了讀寫檔案函式的相關知識,參考的書籍是周立功寫的 嵌入式linux開發教程 上冊 第11.3節。1.open函式和creat函式 因為creat函式可以用open函式來實現,所以就不再去理會它了。關於open函式,記憶起來可以拆解成幾點 a 有int型返回值,返回的是所開啟檔案的控制代碼,或...
Linux應用程式設計學習記錄(二)
今天來繼續學習檔案操作的相關api。早上查了下資料,發現現在學的這些api隸屬於posix標準,posix翻譯過來就是可移植作業系統介面,在unix類系統中應用的十分廣泛。處理檔案的api還有很多別的標準,比如ansi c標準,它應該是標準c語言提供的庫函式。在別人的文章中看到,這二者比較起來的話,...
Linux應用程式設計學習記錄(四)
今天開始學習關於程序的相關知識,參考的教材依然是周立功的 嵌入式linux開發教程 上冊 內容相當於第12章。因為沒多少機會寫 來體會,這部分內容可能會比較抽象,難以理解。總之乙個乙個來吧。初識程序 1.程序是乙個已經開始執行,但是還沒終止的程式例項。2.程序是乙個動態的實體,它是如何從靜態的程式轉...