概念
-
文件I/O稱之為不帶緩存的IO(unbuffered I/O)淹禾。不帶緩存指的是每個read,write都調用內核中的一個系統(tǒng)調用茴扁。也就是一般所說的低級I/O——操作系統(tǒng)提供的基本IO服務铃岔,與os綁定,特定于linix或unix平臺峭火。但是這個不帶緩存表示用戶不緩存德撬,不代表操作系統(tǒng)沒有緩存。
-
標準io是ANSI C建立的一個標準I/O模型躲胳,是一個標準函數(shù)包和stdio.h頭文件中的定義蜓洪,具有一定的可移植性。標準I/O庫處理很多細節(jié)坯苹。例如緩存分配隆檀,以優(yōu)化長度執(zhí)行I/O等。標準的I/O提供了三種類型的緩存粹湃。
- 全緩存:當填滿標準I/O緩存后才進行實際的I/O操作恐仑。
- 行緩存:當輸入或輸出中遇到新行符時,標準I/O庫執(zhí)行I/O操作为鳄。
- 不緩存:stderr就是了裳仆。
區(qū)別
- 文件I/O 又稱為低級磁盤I/O,遵循POSIX相關標準孤钦。
- 標準I/O被稱為高級磁盤I/O歧斟,遵循ANSI C相關標準
- 通過文件I/O讀寫文件時,每次操作都會執(zhí)行相關系統(tǒng)調用偏形。這樣處理的好處是直接讀寫實際文件静袖,壞處是頻繁的系統(tǒng)調用會增加系統(tǒng)開銷,標準I/O可以看成是在文件I/O的基礎上封裝了緩沖機制俊扭。先讀寫緩沖區(qū)队橙,必要時再訪問實際文件,從而減少了系統(tǒng)調用的次數(shù)。
- 文件I/O中用文件描述符表現(xiàn)一個打開的文件捐康,可以訪問不同類型的文件如普通文件仇矾、設備文件和管道文件等。而標準I/O中用FILE(流)表示一個打開的文件解总,通常只用來訪問普通文件贮匕。
API區(qū)別:
文件io
#include <fcntl.h>
#include <unistd.h>
int open(const char *pathname, int oflag, ... mode_t mode);
#成功返回文件描述符, 失敗返回-1
int close(int filedes);
#成功返回0倾鲫, 失敗返回-1
off_t lseek(int filedes, off_t offset, int whence);
#成功返回新的文件偏移量粗合,出錯返回-1
ssize_t read(int filedes, void *buf, size_t nbytes);
#成功則返回讀取到的字節(jié)數(shù)萍嬉,若已到文件的結尾返回0乌昔,出錯返回-1
ssize_t write(int filedes, void *buf, size_t nbytes);
#成功則返回寫入的字節(jié)數(shù),出錯返回-1
標準io
- 除非引用終端設別壤追,否則系統(tǒng)默認流打開是全緩沖的磕道。
打開
#include <stdio.h>
#fopen 打開一個指定的文件
FILE *fopen(const char *restrict pathname, const char *restrict type);
#freopen 在一個指定的流上打開一個文件,比如在標準輸出流上打開某文件
FILE *freopen(const char *restrict pathname, const char *restrict type, FILE *restrict fp);
#dopen 打開指定的文件描述符代表的文件行冰。常用于讀取管道或者其他特殊類型的文件溺蕉,因為這些文件不能直接用fopen打開。
FILE *dopen(int filedes, const char *type);
# 成功返回FILE類型指針悼做,出錯返回NULL
# type 參數(shù)指定操作類型疯特,入讀寫,追加等等肛走。
關閉
#include <stdio.h>
int flose(FILE *fp);
# 成功返回0漓雅,出錯返回EOF
每次一個字符的io
#include <stdio.h>
每次一個字符的IO流
輸入
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
#上面三個函數(shù)的返回值為int,因為EOF常實現(xiàn)為-1朽色,返回int就能與之比較
判斷出錯或者結束
int ferror(FILE *fp);
int feof(FILE *fp);
void clearerr(FILE *fp);
#清除error或者eof標志
輸出
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);
每次一行的IO流
#include <stdio.h>
#輸入
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *buf);
#gets由于沒有指定緩沖區(qū)邻吞,所以有可能造成緩沖區(qū)溢出,要小心
#輸出
int fputs(char *restrict buf, FILE *restrict fp);
int puts(const char *buf);
#格式化輸出IO流
printf 輸出到標準輸出
fprintf 輸出到指定流
sprintf 輸出到指定數(shù)組
snprintf 輸出到指定數(shù)組并在數(shù)組的尾端自動添加一個null字節(jié)
#格式化輸入IO流
scanf 從標準輸入獲取
fscanf 從指定流獲取
sscanf 從指定數(shù)組獲取
網(wǎng)絡高級io
#include <sys/socket.h>
ssize_t recv(int sockfd, void * buff, size_t nbytes, int flags);
success return recv-byte-count, error return -1
ssize_t send(int sockfd, const void * buff, size_t nbytes, int flags);
success return send-byte-count, error return -1
flags:
MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL
/* if system support MSG_WAITALL */
#define readn(fd, ptr, n) recv(fd, ptr, n, MSG_WAITALL)
#include <sys/uio.h>
ssize_t readv(int fileds, const struct iovec * iov, int iovcnt);
success return total-read-byte-count, error return -1
ssize_t writev(int fileds, const struct iovec * iov, int iovcnt);
success return total-write-byte-count, error return -1
struct iovec {
void * iov_base; /* starting address of buffer */
size_t iov_len; /* size of buffer */
};
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags);
success return recv-byte-count, error return -1
ssize_t sendmsg(int sockfd, struct msghdr * msg, int flags);
success return send-byte-count, error return -1
struct msghdr {
void * msg_name; /* protocol address */
socklen_t msg_namelen; /* size of protocol address (val-ret)*/
struct iovec * msg_iov; /* scatter/gather array */
int msg_iovlen; /* element-count in msg_iov */
void * msg_control; /* ancillary data (cmsghdr struct) */
socklen_t msg_controllen; /* length of ancillary data */
int msg_flags; /* flags returned by recvmsg() */
...
};
flags:
MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL
msg_flags:
MSG_DONTROUTE, MSG_DONTWAIT, MSG_OOB, MSG_PEEK, MSG_WAITALL
MSG_BCAST, MSG_MCAST, MSG_TRUNC, MSG_CTRUNC, MSG_EOR, MSG_NOTIFICATION
struct cmsghdr {
socklen_t cmsg_len; /* length in bytes, including this structure */
int cmsg_level; /* originating protocol */
int cmsg_type; /* protocol-specific type */
/* followed by unsigned char cmsg_data[] */
};
#include <sys/socket.h>
#include <sys/param.h> /* for ALIGN macro on many implementations */
struct cmsghdr * CMSG_FIRSTHDR(struct msghdr * mhdrptr);
struct cmsghdr * CMSG_NXTHDR(struct msghdr * mhdrptr,
struct cmsghdr * cmsgptr);
unsigned char * CMSG_DATA(struct cmsghdr * cmsgptr);
unsigned int CMSG_LENGTH(unsigned int length);
unsigned int CMSG_SPACE(unsigned int length);
usage:
struct msghdr msg;
struct cmsghdr * cmsgptr;
/* fill in msg structure */
/* call recvmsg() */
for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
if (cmsgptr->cmsg_level == ... &&
cmsgptr->cmsg_type == ...) {
u_char * ptr = CMSG_DATA(cmsgptr);
/* process data */
}
}
/dev/poll - interface:
#include <sys/devpoll.h>
struct dvpoll {
struct pollfd * dp_fds;
int dp_nfds;
int dp_timeout;
};
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
int kqueue(void);
int kevent(int kq, const struct kevent * changelist, int nchanges,
struct kevent * eventlist, int nevents,
const struct timespec * timeout);
void EV_SET(struct kevent * kev, uintptr_t ident, short filter,
u_short flags, u_int fflags, intptr_t data, void * udata);
struct kevent {
uintptr_t ident;
short filter;
u_short flags;
u_int fflags;
intptr_t data;
void * udata;
};
flags:
EV_ADD, EV_CLEAR, EV_DELETE, (value)
EV_DISABLE, EV_ENABLE, EV_ONESHOT, (value)
EV_EOF, EV_ERROR (result)
filter:
EVFILT_AIO, EVFILT_PROC, EVFILT_READ, EVFILT_SIGNAL,
EVFILT_TIMER, EVFILT_VNODE, EVFILT_WRITE
參考連接:
上下文切換詳解
Unix/Linux中的read和write函數(shù)