文件I/O实践(1) --基础API
什么是I/O
輸入/輸出是內存和外設之間拷貝數據的過程:
? ?設備->內存:?輸入操作
? ?內存->設備:?輸出操作
?高級I/O:?ANSI?C提供的標準I/O庫函數成為高級I/O,?也稱為帶緩沖的I/O;
?低級I/O:?Linux?提供的系統調用,?通常也稱為不帶緩沖的I/O;
?
文件描述符
? 對于Linux內核而言,?所有的文件或設備都對應一個文件描述符(Linux的設計哲學:?一切皆文件),?這樣可以簡化系統編程的復雜程度;
? 當打開/創建一個文件的時候,?內核向進程返回一個文件描述符(是一個非負整數).?后續對文件的操作只需通過該文件描述符即可進行,?內核記錄有關這個打開文件的信息;
? 一個進程啟動時,?默認已經打開了3個文件,?標準輸入(0,?STDIN_FILENO),?標準輸出(1,?STDOUT_FILENO),?標準錯誤輸出(2,?STDERR_FILENO),?這些常量定義在unistd.h頭文件中;?
? 其中,?文件描述符基本上是與文件描述指針(FILE*)一一對應的,?如文件描述符0,1,2?對應?stdin,?stdout,?stderr;
?
文件指針與文件描述符的轉換
fileno:?將文件指針轉換成文件描述符
???????int?fileno(FILE?*stream);
fdopen:?將文件描述符轉換成文件指針
???????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);參數:
? ?pathname:? 文件名,?可以包含[絕對/相對]路徑名;
? ?flags: 文件打開模式;
? ?mode: 用來指定對文件所有者,?文件用戶組以及系統中的其他用戶的訪問權限;
注意:?newMode?=?mode?&?~umask
?
flags常用值
[附]
(1).?umask?API
? ?//改變umask值
? ?mode_t?umask(mode_t?mask);
(2).?ulimit?-a
? ?查看系統中的各種限制;
? ?其中-n:?查看一個進程所能夠打開的最大文件數
(3).?cat?/proc/sys/fs/file-max?
? ?查看一個系統能夠支持的最大打開文件數(該數與內存大小有關)
2.close
#include <unistd.h> int close(int fd);關閉文件描述符,?使得文件描述符得以重新利用
?
3.read
ssize_t read(int fd, void *buf, size_t count);返回值:
? 錯誤:?-1
? 到達文件尾:?0
? 成功:?返回從文件復制到規定緩沖區的字節數
?
4.wirte
ssize_t write(int fd, const void *buf, size_t count);返回值:
? ?錯誤:?-1
? ?什么都沒做:?0
? ?成功:?返回成功寫入文件的字節數
?
注意:
? ?write返回大于0時,?并不代表buf的內容已經寫入到磁盤上的文件中了,?其僅僅代表buf中的數據已經copy到相應的內核緩沖區了.?要實現將緩沖區的內容真正”沖洗”到磁盤上的文件,?需要調用fsync函數;
? ? ?int?fsync(int?fd);
? ?其將內核緩沖區中尚未寫入磁盤的內容同步到文件系統中;
? ?其實在open調用的時候也可以指定同步選項: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的內容真正的寫入到磁盤才真正返回;
//示例: 帶有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;} }文件的隨機讀寫
5.lseek
對應于C庫函數中的fseek,?通過指定相對于當前位置,?末尾位置或開始位置的字節數來重定位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: 產生空洞文件 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");//創建一個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結構的指針,?它包含指定目錄的下一個連接的細節;
? ?沒有更多連接時,?返回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:?關閉目錄 ??
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更改權限
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);總結
以上是生活随笔為你收集整理的文件I/O实践(1) --基础API的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 岁月划过生命线(从0到阿里)
- 下一篇: [置顶] 设计模式之结