文件I/O实践(1) --基础API
什么是I/O
輸入/輸出是內(nèi)存和外設(shè)之間拷貝數(shù)據(jù)的過程:
? ?設(shè)備->內(nèi)存:?輸入操作
? ?內(nèi)存->設(shè)備:?輸出操作
?高級I/O:?ANSI?C提供的標(biāo)準(zhǔn)I/O庫函數(shù)成為高級I/O,?也稱為帶緩沖的I/O;
?低級I/O:?Linux?提供的系統(tǒng)調(diào)用,?通常也稱為不帶緩沖的I/O;
?
文件描述符
? 對于Linux內(nèi)核而言,?所有的文件或設(shè)備都對應(yīng)一個文件描述符(Linux的設(shè)計哲學(xué):?一切皆文件),?這樣可以簡化系統(tǒng)編程的復(fù)雜程度;
? 當(dāng)打開/創(chuàng)建一個文件的時候,?內(nèi)核向進(jìn)程返回一個文件描述符(是一個非負(fù)整數(shù)).?后續(xù)對文件的操作只需通過該文件描述符即可進(jìn)行,?內(nèi)核記錄有關(guān)這個打開文件的信息;
? 一個進(jìn)程啟動時,?默認(rèn)已經(jīng)打開了3個文件,?標(biāo)準(zhǔn)輸入(0,?STDIN_FILENO),?標(biāo)準(zhǔn)輸出(1,?STDOUT_FILENO),?標(biāo)準(zhǔn)錯誤輸出(2,?STDERR_FILENO),?這些常量定義在unistd.h頭文件中;?
? 其中,?文件描述符基本上是與文件描述指針(FILE*)一一對應(yīng)的,?如文件描述符0,1,2?對應(yīng)?stdin,?stdout,?stderr;
?
文件指針與文件描述符的轉(zhuǎn)換
fileno:?將文件指針轉(zhuǎn)換成文件描述符
???????int?fileno(FILE?*stream);
fdopen:?將文件描述符轉(zhuǎn)換成文件指針
???????FILE?*fdopen(int?fd,?const?char?*mode);
//示例 int main() {cout << "fileno(stdin) = " << fileno(stdin) << endl;cout << "fileno(stdout) = " << fileno(stdout) << endl;cout << "fileno(stderr) = " << fileno(stderr) << endl;return 0; }文件I/O?API
1.open
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);參數(shù):
? ?pathname:? 文件名,?可以包含[絕對/相對]路徑名;
? ?flags: 文件打開模式;
? ?mode: 用來指定對文件所有者,?文件用戶組以及系統(tǒng)中的其他用戶的訪問權(quán)限;
注意:?newMode?=?mode?&?~umask
?
flags常用值
[附]
(1).?umask?API
? ?//改變umask值
? ?mode_t?umask(mode_t?mask);
(2).?ulimit?-a
? ?查看系統(tǒng)中的各種限制;
? ?其中-n:?查看一個進(jìn)程所能夠打開的最大文件數(shù)
(3).?cat?/proc/sys/fs/file-max?
? ?查看一個系統(tǒng)能夠支持的最大打開文件數(shù)(該數(shù)與內(nèi)存大小有關(guān))
2.close
#include <unistd.h> int close(int fd);關(guān)閉文件描述符,?使得文件描述符得以重新利用
?
3.read
ssize_t read(int fd, void *buf, size_t count);返回值:
? 錯誤:?-1
? 到達(dá)文件尾:?0
? 成功:?返回從文件復(fù)制到規(guī)定緩沖區(qū)的字節(jié)數(shù)
?
4.wirte
ssize_t write(int fd, const void *buf, size_t count);返回值:
? ?錯誤:?-1
? ?什么都沒做:?0
? ?成功:?返回成功寫入文件的字節(jié)數(shù)
?
注意:
? ?write返回大于0時,?并不代表buf的內(nèi)容已經(jīng)寫入到磁盤上的文件中了,?其僅僅代表buf中的數(shù)據(jù)已經(jīng)copy到相應(yīng)的內(nèi)核緩沖區(qū)了.?要實現(xiàn)將緩沖區(qū)的內(nèi)容真正”沖洗”到磁盤上的文件,?需要調(diào)用fsync函數(shù);
? ? ?int?fsync(int?fd);
? ?其將內(nèi)核緩沖區(qū)中尚未寫入磁盤的內(nèi)容同步到文件系統(tǒng)中;
? ?其實在open調(diào)用的時候也可以指定同步選項:O_SYNC? O_SYNC?The?file?is?opened?for?synchronous?I/O.???Any??write(2)s??on??the??resulting??file??descriptor?will?block?the?calling?process?until?the?data?has?been?physically?written?to?the?underlying?hardware.
? ?write會等到將buf的內(nèi)容真正的寫入到磁盤才真正返回;
//示例: 帶有O_SYNC選項 int main(int argc, char *argv[]) {if (argc < 3){cerr << "Usage : " << argv[0] << " src dest" << endl;exit(EXIT_FAILURE);}int infd = open(argv[1], O_RDONLY);if (infd == -1)err_exit("file O_RDONLY error");int outfd = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC|O_SYNC, 0666);if (outfd == -1)err_exit("file O_WRONLY error");char buf[1024];int readBytes, writeBytes;while ((readBytes = read(infd, buf, sizeof(buf))) > 0){writeBytes = write(outfd, buf, readBytes);cout << "readBytes = " << readBytes<< ", writeBytes = " << writeBytes << endl;} }文件的隨機(jī)讀寫
5.lseek
對應(yīng)于C庫函數(shù)中的fseek,?通過指定相對于當(dāng)前位置,?末尾位置或開始位置的字節(jié)數(shù)來重定位currp:
off_t lseek(int fd, off_t offset, int whence);返回值:?新的文件偏移值;
?
Whence取值:
SEEK_SET
? ?The?offset?is?set?to?offset?bytes.
SEEK_CUR
? ?The?offset?is?set?to?its?current?location?plus?offset?bytes.
SEEK_END
? ?The?offset?is?set?to?the?size?of?the?file?plus?offset?bytes.
//示例1 int main(int argc, char *argv[]) {int fd = open("test.txt", O_RDONLY);if (fd == -1)err_exit("open error");char buf[1024] = {0};int readBytes = read(fd, buf, 5);cout << "readBytes = " << readBytes << ", buf: " << buf << endl;int seekCount = lseek(fd, 0, SEEK_CUR);cout << "current offset = " << seekCount << endl; } //示例2: 產(chǎn)生空洞文件 int main(int argc, char *argv[]) {int fd = open("hole.txt", O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0666);if (fd == -1)err_exit("open error");if (write(fd, "ABCDE", 5) == -1)err_exit("first write error");//創(chuàng)建一個1G的文件if (lseek(fd, 1024*1024*1024, SEEK_CUR) == -1)err_exit("lseek error");if (write(fd, "Hello", 5) == -1)err_exit("second write error");close(fd); }[附]
-查看hole.txt文件
? od?-c?hole.txt
??cat?-A?hole.txt
-查看該文件大小
??du?-h?hole.txt
??du?-b?hole.txt
??du?-k?hole.txt
??du?-m?hole.txt
?
目錄訪問
6.opendir
#include <sys/types.h>#include <dirent.h>DIR *opendir(const char *name);返回值:
? ?成功: 返回目錄指針;
? ?失敗: 返回NULL;
?
7.readdir
struct dirent *readdir(DIR *dirp);返回值:
? ?成功:?返回一個指向dirent結(jié)構(gòu)的指針,?它包含指定目錄的下一個連接的細(xì)節(jié);
? ?沒有更多連接時,?返回0;
struct dirent {ino_t d_ino; /* inode number */off_t d_off; /* not an offset; see NOTES */unsigned short d_reclen; /* length of this record */unsigned char d_type; /* type of file; not supportedby all filesystem types */char d_name[256]; /* filename */ };8.closedir:?關(guān)閉目錄 ??
int closedir(DIR *dirp); //示例: 簡單的ls程序 int main(int argc, char *argv[]) {if (argc < 2){cerr << "Usage : " << argv[0] << " <directory>" << endl;exit(EXIT_FAILURE);}DIR *dir = opendir(argv[1]);if (dir == NULL)err_exit("opendir error");struct dirent *ent;while ((ent = readdir(dir)) != NULL){//過濾掉隱藏文件if (ent->d_name[0] == '.')continue;cout << ent->d_name << "\ti-node: " << ent->d_ino<< ", length: " << ent->d_reclen << endl;}closedir(dir); }9.mkdir
int mkdir(const char *pathname, mode_t mode);10.rmdir:?刪除空目錄
int rmdir(const char *pathname);11.?Chmod,?fchmod更改權(quán)限
int chmod(const char *path, mode_t mode); int fchmod(int fd, mode_t mode);12.chown,fchown更改文件所有者/所屬組
int chown(const char *path, uid_t owner, gid_t group); int fchown(int fd, uid_t owner, gid_t group);總結(jié)
以上是生活随笔為你收集整理的文件I/O实践(1) --基础API的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 岁月划过生命线(从0到阿里)
- 下一篇: 基于SCVMM对虚拟化服务器与虚拟机管理