文件IO编程—非缓冲IO
2.1、概念
文件IO编程
通过使用系统调用中的函数接口对文件操作
标准IO通过文件指针操作文件,与标准IO不同的是,在文件IO中,操作文件是通过文件描述符。
文件描述符
是一个非负的正数,当打开一个现存文件或创建一个新文件时,内核向进程(程序)返回一个文件描述符
2.2、打开文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags); //只是打开文件,文件不存在时,不会创建
int open(const char *pathname, int flags, mode_t mode); //如果文件不存在,需要创建文件用
//参数1:pathname -----要打开的文件
//参数2:flags ------ 打开的方式:
O_RDONLY:只读方式打开文件。
O_WRONLY:可写方式打开文件。
O_RDWR:读写方式打开文件
O_CREAT:如果该文件不存在,就创建一个新的文件,并用第三的参数为其设 置权限。
O_EXCL:如果使用O_CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在。
O_NOCTTY:使用本参数时,如文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端。
O_TRUNC:如文件已经存在,那么打开文件时先删除文件中原有数据 ,类似于fopen中的"w"
O_APPEND:以添加方式打开文件,所以对文件的写操作都在文件的末尾进行,,类似于fopen中的"a"
//参数3:mode ------ 当第二个参数flags中包含:O_CREAT时,需要用到参数mode,mode表示创建文件的权限
//返回值:成功---返回最小的没有被使用的文件描述符,失败:-1
例如:
int main(int argc,char **argv)
{
int fd;
//fd = open(argv[1],O_RDONLY|O_CREAT,0664); //以只读方式打开,如果不存在,则创建
//fd = open(argv[1],O_WRONLY|O_CREAT,0664); //以只写方式打开,如果不存在,则创建
//fd = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,0664); //以只写方式打开,如果不存在,则创建,如果存在,则清空,类似于fopen()的"w"
fd = open(argv[1],O_WRONLY|O_CREAT|O_APPEND,0664); //以只写方式打开,如果不存在,则创建,如果存在,则追加,类似于fopen()的"a"
if(fd < 0){
perror("open");
exit(1);
}
return 0;
}
2.3、关闭文件
#include <unistd.h>
int close(int fd);
//参数:fd ----文件描述符
//返回值:成功---0,失败:-1
2.4、读数据
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
//参数1:fd ----- 文件描述符
//参数2:buf ---- 内存空间的地址
//参数3:count ----内存空间的大小
//返回值: 成功--返回读到的字节数,如果到文件末尾,返回0,失败-- -1
例如:
int main(int argc,char **argv)
{
char buf[SIZE];
int ret;
int fd;
#if 0
while(1){
bzero(buf,SIZE);
ret = read(0,buf,SIZE); //键盘输入时,也会接收换行符
if(ret < 0){
perror("read");
exit(1);
}
printf("(%d):%s",ret,buf);
}
#else
//打开文件
fd = open(argv[1],O_RDONLY);
if(fd < 0){
perror("open");
exit(1);
}
//读取文件中的内容,并打印
while(1){
bzero(buf,SIZE);
ret = read(fd,buf,SIZE);
if(ret < 0){
perror("read");
exit(1);
}else if(ret == 0){ //读到文件末尾
close(fd);
break;
}else{
printf("%s",buf);
}
}
#endif
return 0;
}
2.5、写数据
ssize_t write(int fd, const void *buf, size_t count);
//参数1 ---- 文件描述符
//参数2 ---- 要写的数据的地址
//参数3 ---- 要写的数据的长度
//返回值: 成功--写入的数据的长度,失败--- -1
//注意:write在写数据时,有可能会写不够,所以需要分多次写入,通常会重写write函数,保证要写的数据全部被写进去
例如:
#define SIZE 100
int my_write(int fd, char *buf,size_t count)
{
int ret = 0,size = count;
do{
ret = write(fd,buf+ret,count);
if(ret < 0){
perror("write");
return ret;
}else{
if(ret != count){
count = count-ret;
continue;
}else
break;
}
}while(1);
return size;
}
int main(int argc,char **argv)
{
char buf[SIZE];
int ret;
int fd;
//打开文件
fd = open(argv[1],O_WRONLY|O_CREAT,0664); //文件不存在则创建,文件存在,直接打开
if(fd < 0){
perror("open");
exit(1);
}
//从键盘输入数据,并写入文件中
while(1){
bzero(buf,SIZE);
printf("请输入数据:");
fgets(buf,SIZE,stdin);
buf[strlen(buf)-1] = '\0'; //去掉fgets获取的换行符
if(!strncmp(buf,"quit",4))
break;
ret = my_write(fd,buf,strlen(buf));
if(ret < 0){
perror("my_write");
exit(1);
}
}
return 0;
}
//练习:用文件IO相关函数实现文件拷贝
2.6、设置文件位移量
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
//参数1 ------ 文件描述符
//参数2 ------ 要设置的文件位移量
//参数3 ------ 文件位移量偏移的基点:
SEEK_SET ----从文件起始位置偏移offset
SEEK_CUR ----从当前位置偏移offset
SEEK_END ----从文件末尾偏移offset
//使用lseek函数创建空洞文件
//空洞文件----空内容为空的文件,但是占用了一定的磁盘大小
//如何创建空洞文件,例如:
int main(int argc,char **argv)
{
char buf[SIZE] = "end";
int fd;
//1,打开文件
fd = open(argv[1],O_WRONLY|O_CREAT,0664); //不能以追加方式打开文件
if(fd < 0){
perror("open");
exit(1);
}
//2,修改文件当前的位移量
lseek(fd,1024,SEEK_SET);
//3,写入一个结束标志数据
write(fd,buf,strlen(buf));
return 0;
}
2.7、dup和dup2的用法
2.7.1、赋值文件描述符
int dup(int oldfd);
//参数:oldfd ------被复制的文件描述符
//返回值;成功--新的没有被使用的最小的文件描述符,它是oldfd的一个拷贝,失败--- -1
//接续写
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SIZE 100
int main(int argc,char **argv)
{
char buf[SIZE] = "hello world";
int fd,newfd;
#if 1
write(STDOUT_FILENO,buf,strlen(buf));
fd = dup(STDOUT_FILENO); //复制文件描述符STDOUT_FILENO,得到一个新的文件描述符fd
write(fd,"farsight",8);
#else
//1,打开文件
fd = open(argv[1],O_WRONLY|O_CREAT,0664); //文件不存在则创建,文件存在,直接打开
if(fd < 0){
perror("open");
exit(1);
}
write(fd,buf,strlen(buf));
newfd = dup(fd); //复制fd中保存的文件描述符,返回新的文件描述符保存到newfd中
write(newfd,"farsight",8);
#endif
return 0;
}
//运行结果:
(第一部分是屏幕上打印)
hello worldfarsightesdon@ubuntu:/mnt/hgfs/tolinux$
(第二部分是输出到一个文件,文件内容为)
hello worldfarsight
2.7.2、文件描述符重定向
int dup2(int oldfd, int newfd);
//参数1 ----- 目标:文件描述符
//参数2 ----- 被重定向的文件描述符
//将newfd中的文件描述符重定向到oldfd保存的文件描述符,同时关闭newfd中原来的文件描述符对应的文件
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define SIZE 100
int main(int argc,char **argv)
{
char buf[SIZE] = "helloworld";
int fd,newfd;
fd = open(argv[1],O_WRONLY|O_CREAT,0664);
if(fd < 0){
perror("open");
exit(1);
}
#if 0
newfd = dup(STDOUT_FILENO);//让newfd也指向标准输出
dup2(fd,STDOUT_FILENO);//让标准输出指向fd。
write(STDOUT_FILENO,buf,strlen(buf));
printf("farsight\n");
fflush(stdout);
dup2(newfd,STDOUT_FILENO);//让标准输出重新指向标准输出
printf("welcome to farsight\n");
#else
write(fd,buf,strlen(buf));
newfd = dup(fd);
write(nwfd,"far",3);
#endif
return 0;
}