原文地å€: http://www.hickwu.com/?p=263
作者: Hick
转载请注明出处
p139 å…¶ä»–ç®¡ç†æ–‡ä»¶çš„系统调用
lseek 打开文件以åŽè¯»å–时,有一个文件指针的概念,文件指针决定 read 函数读å–å—符的开始ä½ç½®ï¼Œlseek 函数用æ¥ç§»åŠ¨æ–‡ä»¶æŒ‡é’ˆã€‚
#include <unistd.h>
#include <sys/types.h>
off_t lseek(int fildes, off_t offset, int whence);
offset 为移动的的具体数é‡ï¼Œwhence 决定移动的方å¼ï¼ŒSEEK_SET 表示为ç»å¯¹ä½ç½®ï¼›SEEK_CUR è¡¨ç¤ºç›¸å¯¹å½“å‰æŒ‡é’ˆçš„ä½ç½®ï¼›SEEK_END 表示相对文件末尾 ,移动失败返回 -1 。
有一系列的函数用æ¥è¿”回文件的信æ¯ï¼š fstat, stat, lstat 返回æè¿°æ–‡ä»¶ä¿¡æ¯çš„一个结构(structure),ä¸åŒçš„æ˜¯ fstat 以 fd ä¸ºå‚æ•°ï¼Œè€Œ stat å’Œ lstat ä»¥æ–‡ä»¶è·¯å¾„ä¸ºå‚æ•°ã€‚lstat 相比 stat çš„ä¸åŒæ˜¯ï¼Œå½“文件是一个 link 时,该函数返回的是 link 的信æ¯è€Œä¸æ˜¯ link æŒ‡å‘æ–‡ä»¶çš„ä¿¡æ¯:
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
int fstat(int fildes, struct stat *buf);
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
在ä¸åŒçš„系统下返回的文件信æ¯ç»“æž„å¯èƒ½ä¸ä¸€æ ·ï¼Œä¸è¿‡ä¸€èˆ¬åŒ…å«ä»¥ä¸‹ä¸€äº›æˆå‘˜ï¼š
- st_mode 文件æƒé™å’Œæ–‡ä»¶ç±»åž‹ä¿¡æ¯(目录ã€ä¸€èˆ¬æ–‡ä»¶ã€link ç‰)
- st_ino 文件相关的节点 inode ä¿¡æ¯
- st_dev 文件所在的设备
- st_nlink 文件的硬连接数
å¦å¤–还有文件的所属拥护以åŠç¾¤ç»„ã€è®¿é—®æ—¶é—´ç‰ä¿¡æ¯ï¼Œä¸ä¸€ä¸€åˆ—出。 解释下 ctime 为文件的æƒé™ã€æ‰€å±žç”¨æˆ·æˆ–群组以åŠå†…å®¹çš„æ”¹å˜æ—¶é—´ï¼›mtime 为内容的最åŽä¿®æ”¹æ—¶é—´ã€‚
有一些å®å¯ä»¥ç”¨æ¥æ£€æŸ¥æ–‡ä»¶ç±»åž‹ä¿¡æ¯ï¼š
- S_ISBLK æ£€æŸ¥æ˜¯å¦æ˜¯å—设备文件
- S_ISCHR æ£€æŸ¥æ˜¯å¦æ˜¯å—符设备文件
- S_ISDIR æ£€æŸ¥æ˜¯å¦æ˜¯ç›®å½•文件
- S_ISFIFO æ˜¯å¦æ˜¯ FIFO
- S_ISREG 常规文件
- S_ISLNK link 符å·
示范:
struct stat statbuf;
mode_t modes;
stat(“filenameâ€,&statbuf);
modes = statbuf.st_mode;
if(!S_ISDIR(modes) && (modes & S_IRWXU) == S_IXUSR)
p141 dup å’Œ dup2 用æ¥å¤åˆ¶ fd ,实现多个 fd 指å‘åŒä¸€ä¸ªæ–‡ä»¶ã€‚dup 接收一个 fd 傿•°ï¼Œè¿”回一个新的 fd ï¼›dup2 æŽ¥æ”¶ä¸¤ä¸ªå‚æ•°ï¼Œèƒ½å¤Ÿé«˜æ•ˆçš„æŠŠä¸€ä¸ª fd å¤åˆ¶åˆ°å¦å¤–一个 fd 。在多进程处ç†ç¨‹åºä¸ï¼Œè¿™ä¸¤ä¸ªå‡½æ•°ä¼šéžå¸¸æœ‰ç”¨ï¼ŒåŽè¾¹çš„ç« èŠ‚ä¼šæ¶‰åŠã€‚
p142 æ ‡å‡† io 库 ä½¿ç”¨æ ‡å‡† io 库需è¦åŒ…å«å¤´æ–‡ä»¶ stdio.h ã€‚è·Ÿç³»ç»Ÿè°ƒç”¨ç±»ä¼¼ï¼Œæ ‡å‡†åº“æ“作文件也需è¦å…ˆæ‰“开一个文件,stream 作为 fd çš„æ ‡å‡†åº“ç‰ˆï¼Œç”¨æ¥è¡¨ç¤ºä¸€ä¸ªæ‰“开的文件。stream 是用指针实现的,指å‘åŒ…å«æ–‡ä»¶ä¿¡æ¯çš„一个结构: FILE * 。
系统å¯åŠ¨ä¸€ä¸ªè¿›ç¨‹çš„æ—¶å€™ä¼šæ‰“å¼€ä¸‰ä¸ªæ–‡ä»¶ï¼š stdin, stdout, stderr ï¼Œä¹Ÿå°±æ˜¯å¯¹åº”ç³»ç»Ÿè°ƒç”¨ä¸æ¶‰åŠçš„三个 fd: 0, 1, 2 。
p143 fopen 是模拟系统调用 open 的库函数,一般åªå»ºè®®ç”¨æ¥åšä¸€èˆ¬çš„æ–‡ä»¶ä»¥åŠæ ‡å‡†è¾“入输出æ“作。其他 linux 文件的æ“作建议用系统调用或者其他库。 fopen 的函数原型:
#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
mode 的相关å–值说明(上é¢çš„ b 都是表示二进制文件):
- r/rb åªè¯»æ–¹å¼æ‰“å¼€
- w/wb å†™æ–¹å¼æ‰“开,并把文件截为空
- a/ab è¿½åŠ å†™æ–¹å¼æ‰“å¼€
- r+/rb+ è¯»å†™æ–¹å¼æ‰“å¼€
- w+/wb+ è¯»å†™æ–¹å¼æ‰“开并把文件截为空
- a+/ab+ è¯»å†™æ–¹å¼æ‰“å¼€ï¼Œå†™æ–‡ä»¶è¿½åŠ åˆ°æ–‡ä»¶æœ«å°¾
æ³¨æ„ c è¯è¨€é‡ŒåŒæ ·ä¸€ä¸ªå—æ¯ï¼Œå¯ä»¥æ˜¯å—符串也å¯ä»¥æ˜¯å—符,这里的 mode è¦æ±‚是å—符串。跟 fd ä¸€æ ·ï¼Œæ‰“å¼€çš„ stream 也有数é‡é™åˆ¶ï¼Œå…·ä½“是通过 stdio.h ä¸å®šä¹‰çš„ FOPEN_MAX æ¥å†³å®šçš„。
fread æŒ‰ç…§æŒ‡å®šé•¿åº¦è¯»å–æ–‡ä»¶:
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream);
从指定的 stream ä¸è¯»å– niterms 个大å°ä¸º size 的数æ®è®°å½•,返回æ“作æˆåŠŸçš„è®°å½•æ•° — 注æ„䏿˜¯ read å‡½æ•°çš„è¿”å›žè¯»å–æˆåŠŸçš„å—节数,读å–到的å—符串ä¿å˜åˆ° ptr ä¸ã€‚
fwrite 跟 fread 类似:
#include <stdio.h>
size_t fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream);
fclose 用æ¥å…³é—一个 stream, å› ä¸º io 有 buffer, æ‰€ä»¥å…³é— fd 之å‰ï¼Œ buffer 䏿²¡æœ‰å†™å…¥æ–‡ä»¶çš„æ•°æ®ä¼šè¢«å†™è¿›åŽ»ã€‚ä¸€èˆ¬æ¥è¯´ï¼Œå³ä½¿ä¸æ˜¾å¼çš„ fclose æ–‡ä»¶ï¼Œç¨‹åºæ‰§è¡Œå®Œæ¯•以åŽä¹Ÿä¼šå…³é—相关 stream ,当然ä¸èƒ½å¤Ÿä¾èµ–è¿™æ ·çš„è‡ªåŠ¨å¤„ç†ã€‚
p144 fflush å‡½æ•°ç”¨æ¥æŠŠ buffer 的修改应用到文件上,实际上 fclose 之å‰ä¼šè‡ªåŠ¨è°ƒç”¨è¯¥å‡½æ•°ï¼Œæ‰€ä»¥å¦‚æžœæ²¡æœ‰ç‰¹æ®Šå¿…è¦ï¼Œä¸éœ€è¦æ˜¾å¼è°ƒç”¨ fflush 。
p145 fseek 跟系统调用 lseek 类似,而且ä¸è·Ÿ fread å’Œ fwrite ä¸€æ ·æ˜¯ä»¥æ•°æ®è®°å½•为æ“作å•元。跟 lseek 的主è¦ä¸åŒæ˜¯ lseek 返回实际的åç§»é‡ï¼Œè€Œ fseek æ“作æˆåŠŸæ—¶è¿”å›ž 0 ,失败返回 -1 。
è¿˜æœ‰ä¸‰ä¸ªè¯»å– stream ä¿¡æ¯ä¸çš„æ•°æ®çš„函数 fgetc, getc, getchar 。fgetc 获得 stream 的下一个å—符串,如果读到了文件末尾或者å‘生错误,则返回 EOF ,这时候需è¦é€šè¿‡ ferror å’Œ feof æ¥åŒºåˆ†å…·ä½“是哪ä¸é”™ã€‚
#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
int getchar();
getc 函数跟 fgetc æ•ˆæžœä¸€æ ·ï¼Œåªä¸è¿‡ä»–å¯èƒ½æ˜¯ç”¨å®å®šä¹‰å®žçŽ°çš„ï¼Œä¹Ÿå°±æ˜¯æŸäº›ç³»ç»Ÿä¸‹å¯èƒ½æ˜¯ä¸€ä¸ªå®ã€‚(具体细节ä¸å¤§æ¸…楚) getchar ä¸éœ€è¦å‚æ•°ï¼Œè€Œæ˜¯ç›´æŽ¥ä»Žæ ‡å‡†è¾“å…¥è®¾å¤‡ä»Žè¯»å–一个å—符。
跟上é¢è¯»å–函数想对应,有写入的系列函数 fputc, putc å’Œ putchar 。他们都返回实际写入的å—符,如果失败则返回 EOF ã€‚æ³¨æ„ putchar çš„å‚æ•°åªèƒ½å¤Ÿæ˜¯æ•´æ•°è€Œä¸æ˜¯å—符,这跟 getchar çš„çš„è¿”å›žå€¼æ˜¯ä¸€æ ·ã€‚æ£æ˜¯è¿™æ ·ï¼Œæ‰ä½¿å¾— EOF 的值å¯ä»¥æ˜¯ -1 — 在 char 里,没有对应å—符。
p146 å‰é¢çš„ fgetc 是按照å—符æ¥è¯»åŽ»ï¼Œè¿˜æœ‰ä¸¤ä¸ªå‡½æ•° fgets å’Œ gets å¯ä»¥æŒ‰ç…§å—符串æ¥è¯»å–。
#include <stdio.h>
char *fgets(char *s, int n, FILE *stream);
char *gets(char *s);
fgets 函数从 stream ä¸è¯»å– n -1 个å—符或者读到一行结æŸ(包括文件末尾)。读å–到 n - 1 个å—符以åŽï¼Œä¼šè‡ªåŠ¨è¿½åŠ ä¸€ä¸ª \0 ,表示读å–到的是一个å—符串。最终返回 s 的长度为 n 。fgets 执行æˆåŠŸåˆ™è¿”å›žå‚æ•° s 的指针,达到文件末尾或者出错时都返回空指针(null pointer),出错时还会把错误设置写到 errno ,还有å¥è¯æ²¡æ‰“明白:If the stream is at the end of a file, it sets the EOF indicator for the stream and fgets returns a null pointer. æ²¡å¼„æ‡‚æ€Žä¹ˆæ ‡è®°è¿™ä¸ª EOF 的。
gets 函数的ä¸åŒæ˜¯ä»–ä»Žæ ‡å‡†è¾“å…¥è®¾å¤‡è¯»å–å—ç¬¦ã€‚éœ€è¦æ³¨æ„的是 gets 函数并ä¸é™åˆ¶è¾“入的å—符串大å°ï¼Œè¿™å®¹æ˜“引起问题,一般尽é‡é¿å…使用 gets 而使用 fgets 。
æ ¼å¼åŒ–输入和输出 printf, fprintf, sprintf éƒ½æ˜¯æ ¼å¼åŒ–输出数æ®çš„函数。printf è¾“å‡ºåˆ°æ ‡å‡†è¾“å‡ºè®¾å¤‡ï¼Œfprintf è¾“å‡ºåˆ°å‚æ•°æŒ‡å®šçš„ stream ,sptinf è¾“å‡ºåˆ°å‚æ•°æŒ‡å®šçš„æŒ‡é’ˆ:
#include <stdio.h>
int printf(const char *format, ...);
int sprintf(char *s, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
使用 sprintf æ—¶éœ€è¦æ³¨æ„ s éœ€è¦æœ‰è¶³å¤Ÿçš„长度æ¥ä¿å˜å—ç¬¦ä¸²ã€‚æ ¼å¼åŒ–输出的使用 % ä¸ºæ ‡è¯†å—ç¬¦ï¼Œæ ¼å¼å—符串ä¸éœ€è¦è¾“出 % çš„è¯éœ€è¦è”系两个 % æ¥è¡¨ç¤ºã€‚常è§çš„æ ¼å¼æœ‰ %d 为整型,%o å’Œ %x 分别为整型的八进制和åå…ç¦æ¢è¾“出;$c 为å—符;%s 为å—符串; %f 为浮点型数æ®ã€‚上é¢éƒ½æ˜¯æ¯”较简å•的常è§ç”¨æ³•,通常都å¯ä»¥å¸¦ä¸€äº›ä¿®é¥°ç¬¦ã€‚比如浮点数å¯ä»¥é€šè¿‡ %f2.3 æ¥å®šä¹‰å°æ•°ç‚¹ç‰ã€‚而å—符的输出控制也å¯ä»¥æœ‰ä¿®é¥°ç¬¦ï¼š
%10s "Hello" | Hello|
%-10s "Hello" |Hello |
%10d 1234 | 1234|
%-10d 1234 |1234 |
%010d 1234 |0000001234 |
%10.4f 12.34 | 12.3400|
%10s "HelloTherePeeps" |HelloTherePeeps|
æ³¨æ„æ ¹æ® POSIX 规范,输出ä¸ä¼šè‡ªåŠ¨æˆªå–å—符串长度,所以上é¢çš„æœ€å¥½ä¸€é¡¹èƒ½å¤Ÿè¾“出所有å—符串。
p148 è·Ÿæ ‡å‡†è¾“å‡ºå‡½æ•°å¯¹åº”ï¼Œæœ‰ scanf. fscanf, sscanf ä¸‰ä¸ªè¾“å…¥æ ¼å¼åŒ–函数。注æ„å› ä¸º scanf ä¸éœ€è¦æŒ‡å®šè¾“出信æ¯çš„类型,所以到输入的数æ®ç±»åž‹ä¸å¯¹äº‹ï¼Œå¯èƒ½å¼•起内å˜å´©æºƒ(corrupt)。一般æ¥è¯´ï¼Œscanf 系列函数ä¸å»ºè®®ä½¿ç”¨ï¼Œå˜åœ¨è®¾è®¡ç¼ºé™·ï¼Œä½¿ç”¨ä¸æ–¹ä¾¿å¹¶ä¸”容易导致错误。我们å¯ä»¥ä½¿ç”¨ fread å’Œ fgets æ¥èŽ·å–用户输入信æ¯ã€‚
p149 io æ ‡å‡†åº“è¿˜æä¾›å…¶ä»–函数:
- fgetpos 文件 stream ä¸å½“剿Œ‡é’ˆçš„ä½ç½®
- fsetpos 设置 stream ä¸çš„æŒ‡é’ˆä½ç½®
- ftell Return the current file offset in a stream(没看出æ¥è·Ÿ fgetpos 的差别)
- rewind é‡è®¾æ–‡ä»¶æŒ‡é’ˆä½ç½®
- freopen å¤ç”¨æ–‡ä»¶ stream
- setvbuf: Set the buffering scheme for a stream
- remove è·Ÿ unlink 类似,ä¸è¿‡è¯¥å‡½æ•°è¿˜å¯ä»¥åˆ 除目录
ç”±äºŽä½¿ç”¨æ ‡å‡† io 库时å¯ä»¥åˆ©ç”¨å…¶ç¼“å†²åŠŸèƒ½ï¼ŒåŒæ ·æ˜¯é€ä¸ªå—ç¬¦æ‹·è´æ–‡ä»¶å†…容,用 io 库比调用系统 io è¦å¿«å¾ˆå¤šã€‚