最近這一個月在看《Linux/Unix系統編程手冊》,在學習關於Linux的系統編程。以前學習Linux的時候就打算寫關於Linux的學習記錄,由於以爲本身學得很差,總是寫不出東西。可是如今以爲學習記錄應該堅持寫,慢慢就會有收穫,堅持寫才能夠鍛鍊本身的表達能力。編程
《Linux/Unix系統編程手冊》這本書的評價很高,可是我的以爲翻譯得不太好。其實終究是由於本身的英文閱讀能力太差和沒什麼錢,只能看翻譯版。看了接近一個月,以爲這本書介紹的接口很詳細,程序清單基本會說起到介紹的接口。我的以爲做爲入門書應該是能夠的,起碼看完一遍會有初步的認識,並且做爲參考手冊也不錯。打算看完這本書以後,繼續學習《UNIX環境高級編程》,學無止境。app
第1章:函數
介紹了一些歷史,關於Linux、Unix和C;還有一些標準POSIX、SUS post
第2章:學習
介紹Linux和Unix的一些基本概念。測試
1.操做系統的兩個含義:一,包含管理和分配計算機資源的核心層軟件和附帶的全部標準軟件;二,僅僅指管理和分配計算機資源的核心層軟件。spa
2.內核的做用:進程調度、內存管理、文件系統、建立和終止進程、對設備的訪問、聯網、提供API。其實就是抽象,用戶經過內核來使用硬件,而不用直接與硬件打交道。操作系統
3.用戶態和內核態。命令行
。。。。。。。。。。。。。。。。還有一堆的概念。。。。。。。。。。。。。。。。。。。
第3章
介紹系統編程的概念。
系統調用(systerm calls)是用戶程序與操做系統之間的接口,系統調用在內核態。庫函數(library functions),一些庫函數是經過系統調用來實現,好處是提供了比底層系統調用更方便的接口。
還有本書的代碼所需的一些函數、頭文件。。。。。。。。。。。
第4章
介紹了文件I/O。
文件描述符,用來表示已經打開的文件(全部類型),是一非負整數。最基本的文件描述符0(標準輸入)、1(標準輸出)、2(標準錯誤)。
I/O操做:首先經過調用open獲取一個文件描述符,再對該文件描述符進行read或者write操做,最後使用close釋放文件描述符和相關資源。
open()調用,打開一個文件或者建立一個文件。
1 #include <sys/stat.h> 2 #include <fcntl.h> 3 4 int open(const char *pathname, int flags, .../* mode_t mode */);
成功調用返回文件描述符,失敗返回-1;
一、pathname爲打開文件的文件名; flags爲位掩碼,用於指定文件的訪問模式;mode爲位掩碼參數,用於指定文件的訪問權限(可選)。
二、flags位掩碼的標誌分爲文件訪問模式標誌、文件建立標誌、已打開文件的狀態標誌;其中文件訪問模式標誌以下表,這些標誌不能同時使用。
訪問模式 | 描述 |
O_RDONLY | 以只讀方式打開文件 |
O_WRONLY | 以只寫方式打開文件 |
O_RDWR | 以讀寫方式打開文件 |
比較經常使用的標誌還有O_APPEND(老是在文件尾部添加數據)、O_CREAT(若是要打開的文件不存在就新建一個空文件)、O_EXCL(與O_CREAT結合使用代表若是文件已經存在,就不會打開文件)。
三、open()函數的錯誤:省略。
read()調用,從文件描述符對應的文件中讀取數據。
#include <unistd.h> ssize_t read(int fd, void *buffer, size_t count);
fd爲文件描述符;buffer爲存儲數據的緩衝區;count爲最多能讀取的字節數。
成功調用返回實際讀取字節數,遇到文件結束符返回0,出現錯誤返回-1。
PS:要在緩衝區最後添加一個表示終止的空字符。
write()調用,往文件描述符對應的文件寫入數據。
1 #include <unistd.h> 2 3 ssize_t write(int fd, void *buffer, size_t count);
fd爲文件描述符;buffer爲存儲數據的緩衝區;count爲準備從buffer寫入到文件的數據的字節數。
成功調用返回實際寫入文件的字節數, 失敗返回-1。
close()調用,關閉已經打開的文件描述符。
1 #include <unistd.h> 2 3 int close(int fd);
fd爲文件描述符。
成功調用返回0,失敗返回-1 。
全部類型的文件和設備驅動都實現了相同的I/O接口,因此無需針對特殊的文件編寫代碼。
文件偏移量:讀寫偏移量或指針,是執行下一個read和write操做的文件起始位置(相對與文件頭部起始點)。
lseek(),改變文件偏移量。
1 #include <unistd.h> 2 3 off_t lseek(int fd, off_t offset, int whence);
fd爲文件描述符,offset爲偏移量(字節),whence爲代表解釋offset參數的方法。
whence參數:
SEEK_SET | 將文件偏移量設置爲從文件頭起始點開始的offset個字節 |
SEEK_CUR | 相對於當前文件偏移量,再加上offset個字節 |
SEEK_END | 將文件偏移量設置爲起始於文件尾部的offset個字節 |
文件空洞 :當文件的偏移量大於文件的當前長度時,文件結尾到新寫入數據之間的空間稱爲文件空洞。讀取文件空洞的內容會返回以0填充的緩衝區。
「空洞是否佔用磁盤空間由文件系統決定」----《百度百科》
「若是空洞的邊界落在塊內,而非剛好落在塊的邊界上,則會分配一個完整的塊來存儲數據,塊中與空洞相關的部分則以空字節填充」----書本提示
練習:
4-1:tee命令是從標準輸入中讀取數據,直至文件結尾,隨後將數據寫入標準輸入和命令行參數所指定的文件。請使用I/O系統調用實現tee命令,默認狀況下,若已存在命令行參數指定文件同名的文件tee命令會將其覆蓋。如文件以存在,請實現-a命令行選項(tee -a file)在文件結尾出追加數據。
1 /* 2 * ===================================================================================== 3 * 4 * Filename: my_tee.c 5 * 6 * Description: tee 7 * 8 * Version: 1.0 9 * Created: 2014年03月14日 18時23分04秒 10 * Revision: none 11 * Compiler: gcc 12 * 13 * Author: alan (), alan19920626@gmail.com 14 * Organization:若是輸入爲my_tee -a會出現錯誤而不是程序自動中止並且報錯!!!!須要改進!!! 15 * 16 * ===================================================================================== 17 */ 18 19 #include <sys/stat.h> 20 #include <fcntl.h> 21 #include <ctype.h> 22 #include "tlpi_hdr.h" 23 24 #define MAX_READ 20 25 26 int main(int argc, char *argv[]){ 27 int fd, opt; 28 char buf[MAX_READ + 1]; 29 ssize_t numRead; 30 off_t offset; 31 32 if(argc < 2 || strcmp(argv[1], "--help") == 0) 33 usageErr("%s [-a] file"); 34 35 fd = open(argv[argc-1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); 36 if(fd == -1) 37 errExit("open"); 38 39 offset = lseek(fd, 0, SEEK_SET); 40 while((opt = getopt(argc, argv, ":a")) != -1){ 41 switch(opt){ 42 case 'a': 43 //file = optarg; 44 offset = lseek(fd, -1, SEEK_END); 45 break; 46 case '?': 47 default: 48 fprintf(stderr, "%s option: '-%c' is invalid: ignore\n", argv[0], optopt); 49 exit(EXIT_FAILURE); 50 break; 51 } 52 } 53 54 55 while((numRead = read(STDIN_FILENO, buf, MAX_READ)) > 0){ 56 buf[numRead] = '\0'; 57 58 if(write(STDOUT_FILENO, buf, numRead+1) != (numRead+1)) 59 fatal("couldn't write whole buf"); 60 if(write(fd, buf, numRead) != (numRead)) 61 fatal("couldn't write whole buf"); 62 } 63 64 if(numRead == -1) 65 errExit("read"); 66 67 if(close(fd) == -1) 68 errExit("close file"); 69 70 exit(EXIT_SUCCESS); 71 }
測試:
lancelot@debian:~/Code/tlpi$ cat > t1 This is the first line. lancelot@debian:~/Code/tlpi$ cat t1 This is the first line. lancelot@debian:~/Code/tlpi$ ./my_tee t1 This is the second line. This is the second line. This is the third line. This is the third line. lancelot@debian:~/Code/tlpi$ cat t1 This is the second line. This is the third line. lancelot@debian:~/Code/tlpi$ ./my_tee -a t1 This is the append line. This is the append line. lancelot@debian:~/Code/tlpi$ cat t1 This is the second line. This is the third line. This is the append line.
4-2:編寫一個相似cp命令的程序,當使用該程序複製一個包含空洞(連續的空字節)的普通文件時,要求目標文件的空的與源文件保持一致。
1 /* 2 * ===================================================================================== 3 * 4 * Filename: my_cp.c 5 * 6 * Description: 7 * 8 * Version: 1.0 9 * Created: 2014年04月03日 17時02分43秒 10 * Revision: none 11 * Compiler: gcc 12 * 13 * Author: alan (), alan19920626@gmail.com 14 * Organization: 15 * 16 * ===================================================================================== 17 */ 18 19 #include <sys/stat.h> 20 #include <fcntl.h> 21 #include <ctype.h> 22 #include "tlpi_hdr.h" 23 24 #define BUF_SIZE 1024 25 26 int main(int argc, char *argv[]){ 27 int inputFd, outputFd, openFlags; 28 mode_t filePerms; 29 ssize_t numRead; 30 char buf[BUF_SIZE]; 31 32 if(argc != 3 || strcmp(argv[1], "--help") == 0) 33 usageErr("%s old-file new-file\n", argv[0]); 34 35 inputFd = open(argv[1], O_RDONLY); 36 if(inputFd == -1) 37 errExit("open file %s", argv[1]); 38 39 openFlags = O_CREAT | O_WRONLY | O_TRUNC; 40 filePerms = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; 41 outputFd = open(argv[2], openFlags, filePerms); 42 if(outputFd == -1) 43 errExit("open file %s", argv[2]); 44 45 while((numRead = read(inputFd, buf, BUF_SIZE)) > 0) 46 if(write(outputFd, buf, numRead) != numRead) 47 fatal("couldn't write whole buffer"); 48 if(numRead == -1) 49 errExit("read"); 50 if(close(inputFd) == -1) 51 errExit("close input"); 52 if(close(outputFd) == -1) 53 errExit("close output"); 54 55 exit(EXIT_SUCCESS); 56 }
測試:首先經過書本的程序清單提供的seek_io.c來使t2出現空洞。
lancelot@debian:~/Code/tlpi$ cat t2 This is the first line. This is the second line. This is the third line. lancelot@debian:~/Code/tlpi$ gcc -o seek_io seek_io.c error_functions.c get_num.c lancelot@debian:~/Code/tlpi$ ./seek_io t2 s100000 wabc s100000: seek succeeded wabc: wrote 3 bytes lancelot@debian:~/Code/tlpi$ cat t2 This is the first line. This is the second line. This is the third line. abclancelot@debian:~/Code/tlp./seek_io t2 s50000 R5 s50000: seek succeeded R5: 00 00 00 00 00
能夠看到文件偏移量爲50000的內容爲空字節。。。。。
而後進行復制。
lancelot@debian:~/Code/tlpi$ ./my_cp t2 t3 lancelot@debian:~/Code/tlpi$ ls -l t2 t3 -rw-r--r-- 1 lancelot lancelot 100003 4月 3 17:27 t2 -rw-r--r-- 1 lancelot lancelot 100003 4月 3 17:34 t3 lancelot@debian:~/Code/tlpi$ ./seek_io t3 s50000 R5 s50000: seek succeeded R5: 00 00 00 00 00
能夠看到兩個文件的大小相同,並且從t3文件偏移量爲50000開始讀取5個字節都爲空字節。