概念
-
文件I/O称之为不带缓存的IO(unbuffered I/O)。不带缓存指的是每个read,write都调用内核中的一个系统调用。也就是一般所说的低级I/O——操作系统提供的基本IO服务,与os绑定,特定于linix或unix平台。但是这个不带缓存表示用户不缓存,不代表操作系统没有缓存。
-
标准io是ANSI C建立的一个标准I/O模型,是一个标准函数包和stdio.h头文件中的定义,具有一定的可移植性。标准I/O库处理很多细节。例如缓存分配,以优化长度执行I/O等。标准的I/O提供了三种类型的缓存。
- 全缓存:当填满标准I/O缓存后才进行实际的I/O操作。
- 行缓存:当输入或输出中遇到新行符时,标准I/O库执行I/O操作。
- 不缓存:stderr就是了。
区别
- 文件I/O 又称为低级磁盘I/O,遵循POSIX相关标准。
- 标准I/O被称为高级磁盘I/O,遵循ANSI C相关标准
- 通过文件I/O读写文件时,每次操作都会执行相关系统调用。这样处理的好处是直接读写实际文件,坏处是频繁的系统调用会增加系统开销,标准I/O可以看成是在文件I/O的基础上封装了缓冲机制。先读写缓冲区,必要时再访问实际文件,从而减少了系统调用的次数。
- 文件I/O中用文件描述符表现一个打开的文件,可以访问不同类型的文件如普通文件、设备文件和管道文件等。而标准I/O中用FILE(流)表示一个打开的文件,通常只用来访问普通文件。
API区别:
文件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);
#成功则返回读取到的字节数,若已到文件的结尾返回0,出错返回-1
ssize_t write(int filedes, void *buf, size_t nbytes);
#成功则返回写入的字节数,出错返回-1
标准io
打开
#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 参数指定操作类型,入读写,追加等等。
关闭
#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);
#上面三个函数的返回值为int,因为EOF常实现为-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由于没有指定缓冲区,所以有可能造成缓冲区溢出,要小心
#输出
int fputs(char *restrict buf, FILE *restrict fp);
int puts(const char *buf);
#格式化输出IO流
printf 输出到标准输出
fprintf 输出到指定流
sprintf 输出到指定数组
snprintf 输出到指定数组并在数组的尾端自动添加一个null字节
#格式化输入IO流
scanf 从标准输入获取
fscanf 从指定流获取
sscanf 从指定数组获取
网络高级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函数