目錄
1.什么是文件偏移量?
1.1 文件偏移量介紹
1.2 文件偏移量重點(diǎn)
1.3 文件偏移量工作原理
2.文件偏移量設(shè)置
2.1 lseek函數(shù)
2.2?lseek內(nèi)核源碼分析
3.寫文件
3.1 write函數(shù)
3.2 write內(nèi)核源碼分析
4.讀文件
4.1 read函數(shù)
4.2 read內(nèi)核源碼分析
5.文件讀寫,文件偏移量設(shè)置示例代碼
1.什么是文件偏移量?
1.1 文件偏移量介紹
在介紹文件偏移量之前,先來(lái)喊一個(gè)口號(hào):只有真正理解了文件偏移量,你才會(huì)懂得文件讀寫。
文件偏移量是指文件中當(dāng)前讀取或?qū)懭胛恢玫闹甘酒鳌?/p>
在Linux中,每個(gè)打開的文件都有一個(gè)文件偏移量,用于記錄下一次讀取或?qū)懭氩僮鲗⒃谖募邪l(fā)生的位置。文件偏移量是一個(gè)以字節(jié)為單位的整數(shù)值,從文件開頭開始計(jì)算。
當(dāng)執(zhí)行讀取或?qū)懭氩僮鲿r(shí),文件偏移量會(huì)隨之改變。
- 讀取操作會(huì)從文件偏移量所指示的位置開始讀取數(shù)據(jù),并將文件偏移量向后移動(dòng)到讀取操作結(jié)束后的位置。
- 寫入操作則會(huì)從文件偏移量所指示的位置開始寫入數(shù)據(jù),并將文件偏移量向后移動(dòng)到寫入操作結(jié)束后的位置。
- 通過(guò)改變文件偏移量,可以在文件中定位到特定的位置進(jìn)行讀取或?qū)懭氩僮鳌?/li>
1.2 文件偏移量重點(diǎn)
關(guān)于文件偏移量我們需要注意以下幾點(diǎn),只有充分掌握了以下幾點(diǎn)才能進(jìn)行正確的文件讀寫:
- 1.文件偏移量對(duì)應(yīng)的是struct file對(duì)象的f_pos成員,這個(gè)成員由write,read,lseek函數(shù)共享,也就是說(shuō)三個(gè)函數(shù)都會(huì)改變f_pos值。
- 2.open函數(shù)如果設(shè)置O_APPEND標(biāo)識(shí),會(huì)改變write函數(shù)使用f_pos的行為,具體可以參考write內(nèi)核源碼分析。
1.3 文件偏移量工作原理
(1)正常情況下文件偏移量工作原理
?圖 1-1 正常情況下文件偏移量工作原理
(2)設(shè)置O_APPEND情況下文件偏移工作原理
?圖 1-2?設(shè)置O_APPEND情況下文件偏移工作原理
2.文件偏移量設(shè)置
2.1 lseek函數(shù)
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
函數(shù)簡(jiǎn)介:lseek函數(shù)是Linux系統(tǒng)中的一個(gè)文件操作函數(shù),用于改變文件讀寫指針的位置。它可以在文件中任意移動(dòng)讀寫指針,實(shí)現(xiàn)對(duì)文件的隨機(jī)訪問(wèn)。
函數(shù)參數(shù):
fd:文件描述符,指定要進(jìn)行操作的文件。
offset:偏移量,指定要移動(dòng)的字節(jié)數(shù)。正值表示向文件末尾方向移動(dòng),負(fù)值表示向文件起始位置方向移動(dòng)。
whence:起始位置,指定了偏移量的參考位置。它可以取以下三個(gè)值:
- SEEK_SET:從文件起始位置開始計(jì)算偏移量。
- SEEK_CUR:從當(dāng)前讀寫指針位置開始計(jì)算偏移量。
- SEEK_END:從文件末尾位置開始計(jì)算偏移量。
lseek參數(shù)解析:
圖 2-1 lseek參數(shù)解析
函數(shù)返回值:
成功:返回新的讀寫指針位置。
失?。悍祷?1,并設(shè)置errno。
2.2?lseek內(nèi)核源碼分析
?圖 2-2 lseek內(nèi)核源碼分析
lseek內(nèi)核源碼主要流程如圖 2-2,lseek函數(shù)主要工作為更新struct file對(duì)象成員f_ops,Linux一切皆文件,不同的文件類型對(duì)應(yīng)的lseek函數(shù)具體實(shí)現(xiàn)會(huì)不一樣。
lseek,write,read調(diào)用完主要流程都要執(zhí)行f.file->f_pos = pos更新f_pos的值。
3.寫文件
3.1 write函數(shù)
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
函數(shù)簡(jiǎn)介:用于將數(shù)據(jù)寫入文件描述符或設(shè)備。
函數(shù)參數(shù):
fd:文件描述符,要寫入的文件或設(shè)備的標(biāo)符。通常使用open函數(shù)打開文件或設(shè)備后返回的文件描述符作為參數(shù)。
buf:要寫入數(shù)據(jù)的緩沖區(qū)的指針,數(shù)據(jù)將該緩沖區(qū)寫入到文件描述符指定的位置。
count:要寫入的字節(jié)數(shù),即從緩沖區(qū)中寫入的數(shù)據(jù)長(zhǎng)度。
函數(shù)返回值:
成功:返回實(shí)際寫入的字節(jié)數(shù)。
失?。悍祷?1,并設(shè)置errno。
3.2 write內(nèi)核源碼分析
?圖 3-1?write函數(shù)內(nèi)核源碼分析
write函數(shù)內(nèi)核源碼主要流程如圖 3-1,write函數(shù)主要工作為將數(shù)據(jù)寫入文件并更新更新struct file對(duì)象成員f_ops,不同的文件類型對(duì)應(yīng)的write函數(shù)實(shí)現(xiàn)會(huì)不一樣,需要具體情況具體分析。
write函數(shù)有一個(gè)重點(diǎn)就是當(dāng)open函數(shù)設(shè)置O_APPEND標(biāo)識(shí)后,write每次寫數(shù)據(jù)都是從隊(duì)尾開始,這個(gè)特性的實(shí)現(xiàn)是write不會(huì)用struct file對(duì)象成員f_pos指定的位置開始寫文件,而是重新計(jì)算pos(設(shè)置為文件實(shí)際大?。褂胮os指定的位置開始寫文件,根據(jù)內(nèi)核源碼,我們就能很清楚理解O_APPEND標(biāo)識(shí)工作原理。
4.讀文件
4.1 read函數(shù)
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
函數(shù)簡(jiǎn)介:用于從文件描述符中讀取數(shù)據(jù)。
函數(shù)參數(shù):
fd:文件描述符,要讀取的文件或設(shè)備的標(biāo)識(shí)符。通常使用open函數(shù)打開文件或設(shè)備后返回的文件描述符作為參數(shù)。
buf:存放讀取數(shù)據(jù)的緩沖區(qū)的指針。數(shù)據(jù)將從文件描述符指定的位置讀取到該緩沖區(qū)。
count:要讀取的字節(jié)數(shù),即從文件中讀取的數(shù)據(jù)長(zhǎng)度。
函數(shù)返回值:
成功:返回實(shí)際讀取的字節(jié)數(shù)。
失?。悍祷?1,并設(shè)置errno。
4.2 read內(nèi)核源碼分析
?圖 4-1 read函數(shù)內(nèi)核源碼分析
read函數(shù)內(nèi)核源碼主要流程如圖 4-1,read函數(shù)主要工作為從文件讀取并更新更新struct file對(duì)象成員f_ops,不同的文件類型對(duì)應(yīng)的read函數(shù)實(shí)現(xiàn)會(huì)不一樣,需要具體情況具體分析。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-571919.html
5.文件讀寫,文件偏移量設(shè)置示例代碼
本示例模擬圖 1-1和圖 1-2 流程文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-571919.html
#include <sys/types.h>
#include <sys/stat.h>
#include <stdbool.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#define TEST_FILE "/tmp/test.txt"
#define BUF_SIZE (256)
#define READ_BUF_SIZE (2048)
void print_pos(int fd) {
int pos = lseek(fd, 0, SEEK_CUR);
printf("cur pos:%d\n", pos);
}
int write_len_data(int fd, unsigned char len, char ch) {
unsigned char sbuf[BUF_SIZE] = {0};
for (unsigned char i = 0; i < len; i++) {
sbuf[i] = ch;
}
int ret = write(fd, sbuf, len);
if (ret == -1) {
perror("write error");
return -1;
}
return 0;
}
int read_len_data(int fd, unsigned int len) {
if (len > READ_BUF_SIZE) return -1;
char rbuf[READ_BUF_SIZE] = {0};
return read(fd, rbuf, len);
}
int fpos_test(bool append) {
int flags = 0;
if (append) {
flags = O_RDWR | O_CREAT | O_TRUNC | O_APPEND;
} else {
flags = O_RDWR | O_CREAT | O_TRUNC;
}
int fd = open(TEST_FILE, flags, 0777);
if (fd == -1) {
perror("open error");
return -1;
}
write_len_data(fd, 100, 'a');
print_pos(fd);
lseek(fd, 10, SEEK_SET);
read_len_data(fd, 40);
print_pos(fd);
write_len_data(fd, 20, 'b');
print_pos(fd);
close(fd);
return 0;
}
int main(int argc, char *argv[]) {
fpos_test(false);
return 0;
}
到了這里,關(guān)于文件IO_文件讀寫(附Linux-5.15.10內(nèi)核源碼分析)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!