文件IO管理
文件读写 - 系统调用
#include <fnctl.h>
int open(char *pathname, int flags);
int open(char *pathname, int flags, mode_t mode);
flags:
O_RDONLY
O_WRONLY
O_RDWR
O_CREAT
O_DIRECT : Direct I/O, 不加此参数为 Bufferd I/O
#include <fcntl.h>
#include <stdio.h>
int main(void) {
int fd;
fd = open("/opt/c/hello.txt", O_RDONLY);
if (fd == -1)
perror("Error");
else
printf("%d", fd);
}
int create(const char *name, mode_t mode);
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(void) {
int fd;
fd = creat("/opt/c/1.txt", 0644);
// 等同于
// fd = open("/opt/c/1.txt", O_WRONLY | O_CREATE | O_TRUNC, 0644);
return 0;
}
int read(int fd, void *buf, int len);
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
char word[100];
int nr, fd;
fd = open("/opt/c/hello.txt", O_RDONLY);
nr = read(fd, word, 7);
printf("%s", word);
close(fd);
return 0;
}
int write(int fd, const void *buf, int count);
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(void) {
int fd;
char *buf = "My ship is solid!";
fd = open("/opt/c/1.txt", O_RDWR);
write(fd, buf, strlen(buf));
close(fd);
return 0;
}
同步IO
/*
* int fsync(int fd);
* 对当前打开的fd缓冲区数据同步到磁盘
*/
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(void) {
int fd, nr;
char *buf = "Something so beautiful!!";
fd = open("/opt/c/1.txt", O_RDWR);
nr = write(fd, buf, strlen(buf));
if(nr == -1) {
perror("Error");
} else {
fsync(fd);
printf("writed sucessful");
}
close(fd);
return 0;
}
writed sucessful
/*
* void sync(void);
* 将磁盘上所有缓冲区的数据同步到磁盘
*/
#include <unistd.h>
int main(void) {
sync();
return 0;
}
/tmp/tmprzt81yif.c: In function ‘main’:
/tmp/tmprzt81yif.c:11:5: warning: implicit declaration of function ‘sync’ [-Wimplicit-function-declaration]
sync();
^
IO多路复用
select
/*
* 测试select的使用,此处只监控一个I/O(标准输入),并不是多路复用
* 需要到Linux终端上运行
* int select(int n, fd_set *readfs, fd_set *writefds, fd_set *execptfds, struct timeval *timeout);
* n: 监控集合中的最大文件描述符 + 1
* timeout:
struct timeval {
long tv_sec; //seconds
long tv_usec; //microseconds
}
* 当监控的文件描述符I/O未就绪,且处于设定的超时范围内,select()调用就一直阻塞。
* 监控的文件描述符分为3类, 不监控的设置位NULL:
* 1. readfds: 监控是否数据可读取
* 2. writefds: 监控是否写操作可以无阻塞的完成
* 3. exceptfds: 监控是否发生异常
* FD_ZERO() 从指定集合中删除文件描述符
* FD_SET() 向指定集合中添加文件描述符
* FD_ISSET() 判读一个文件描述符是否在指定的集合中
*/
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#define TIMEOUT 5
#define BUF_LEN 1024
#define STDIN_FILENO 0
int main(void) {
struct timeval tv;
fd_set readfds;
int ret;
// wait on stdin for input.
FD_ZERO(&readfds);
FD_SET(STDIN_FILENO, &readfds);
// wait up to five seconds
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
// all right, nou block!
ret = select(
STDIN_FILENO + 1,
&readfds,
NULL,
NULL,
&tv);
if(ret == -1) {
perror("select");
return 1;
} else if(!ret) {
printf("%d seconds elapsed.\n", TIMEOUT);
return 0;
}
// is our file descriptor ready to read?
if(FD_ISSET(STDIN_FILENO, &readfds)) {
char buf[BUF_LEN+1];
int len;
len = read(STDIN_FILENO, buf, BUF_LEN);
if(len == -1) {
perror("read");
return 1;
} else if(len) {
buf[len] = '\0';
printf("read: %s\n", buf);
}
return 0;
}
fprintf(stderr, "This should not happen!\n");
return 1;
}
poll
/*
* int poll(struct pollfd *fds, int nfds, int timeout);
fds: 结构体数组,可以向poll传递多个监控结构体
nfds: 传递的监控结构体个数
timeout: 超时时长,单位ms
*/
#include <stdio.h>
#include <unistd.h>
#include <poll.h>
#define TIMEOUT 5
int main(void) {
struct pollfd fds[2];
int ret;
// watch stdin for input
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
// watch stdout for ability to write
fds[1].fd = STDIN_FILENO;
fds[1].events = POLLOUT;
// all set, block, timeout单位是ms
ret = poll(fds, 2, TIMEOUT*1000);
if(ret == -1) {
perror("poll");
return 1;
}
if(!ret) {
printf("%d seconds elapsed.\n", TIMEOUT);
return 0;
}
if(fds[0].revents & POLLIN) {
printf("stdin is readable\n");
}
if (fds[1].revents & POLLOUT) {
printf("stdout is writeable\n");
}
return 0;
}
文件读写 - C标准库
fopen, fread, fwrite是由C标准库(stdio.h)提供的C库函数
/*
* FILE *fopen(char *path, char *mode)
*/
#include <stdio.h>
int main(void) {
FILE *stream;
// 打开文件流
stream = fopen("/opt/c/1.txt", "r");
if(!stream) {
perror("open");
}
// 关闭文件流
fclose(stream);
}
/*
* int fread(void *buf, int size, int nr, FILE *stream)
*/
#include <stdio.h>
int main(void) {
char buf[8];
int nr;
FILE *stream;
stream = fopen("/opt/c/1.txt", "r");
if(stream)
nr = fread(buf, sizeof(buf), 1, stream);
if(nr)
printf("%s", buf);
fclose(stream);
}
/*
* int fwrite(void *buf, int size, int nr, FILE *stream)
*/
#include <stdio.h>
#include <string.h>
int main(void) {
char buf[100];
int nr;
FILE *stream;
strcpy(buf, "hello, This is beautiful");
stream = fopen("/opt/c/1.txt", "w");
if(stream)
nr = fwrite(buf, sizeof(buf), 1, stream);
if(nr)
printf("write sucessfully");
fclose(stream);
}
write sucessfully
/*
* fopen, fread, fwrite, fclose综合练习
*/
#include <stdio.h>
int main(void) {
FILE *in, *out;
struct person {
char name[50];
unsigned long weight;
char gender;
} zy, zb = {"zhubiao", 80, 'M'};
out = fopen("/opt/c/2.txt", "w");
if(!out) {
perror("fopen");
return 1;
}
if(!fwrite(&zb, sizeof(struct person), 1, out)) {
perror("fread");
return 1;
}
if(fclose(out)) {
perror("fclose");
return 1;
}
in = fopen("/opt/c/2.txt", "r");
if(!in) {
perror("fopen");
return 1;
}
if(!fread(&zy, sizeof(struct person), 1, in)) {
perror("fread");
return 1;
} else {
printf("%s, %c, %d", zy.name, zy.gender, zy.weight);
}
if(fclose(in)){
perror("fclose");
return 1;
}
}
zhubiao, M, 80
存储映射
存储映射是将文件映射到内存中,对文件的读写操作变成对该内存区域的数据的访问,这样做的优点:
a. 使用fread, fwrite涉及到两次拷贝:从内核缓冲区到用户缓冲区,从用户缓冲区到用户读写区域;而使用映射是直接对映射区域进行读写操作
b. 读写映省去系统调用、上下文切换的开销
c. 当多个进程将同一个对象映射到内存中共享时,数据在所有内存间共享
d. 映射对象间搜索时,只是简单的指针操作,不需要系统调用lseek()
mmap()
/*
* void * mmap(void, *addr, int len, int prot, int flags, int fd, int offset);
调用成功返回内存映射的起始地址,失败返回-1
addr: 告诉内核映射文件的最佳内存地址,不是强制性要求,传0由系统决定。
len: 映射len个字节
prot: 控制映射内存区域的访问权限, 不能与文件描述符fd冲突。
PROT_READ: 页可读
PROT_WRITE: 页可写
PROT_EXEC: 页可执行
flags:
MAP_FIXED: 强制使用addr参数,如果无法映射到指定的内存区域,调用失败,不建议使用
MAP_PRIVATE: 映射区域不共享
MAP_SHARED: 映射区域共享,该映射区域会受其他进行写操作的影响。
int munmap(void *addr, size_t len)
调用成功返回0, 失败返回-1
addr: 需取消的内存映射区域首地址,通常是mmap返回的地址
int msync(void *addr, size_t len, int flags);
将映射区域的数据同步到硬盘,等同于fsync()
*/
#include <sys/mman.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
int fd;
void *p;
int len;
len = 5;
fd = open("/opt/c/1.txt", O_RDONLY);
// 存储映射
p = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0);
printf("%s", p);
// 将映射同步到硬盘
msync(p, len, MS_SYNC);
// 取消映射
munmap(p, len);
// 此时再读取该内存区域会报错, printf("%s", p);
return 0;
printf("%d", MAP_FAILED);
}
hello world
someting so beautiful