运行环境:Ubuntu18.04
前言:
对于系统调用,我们对于文件IO需要学习的主要有open()、read()、write()、close()。我们平时使用的库函数其实都是通过系统调用进行封装成各种功能的函数。
1、open()
int open(const char *path, int oflag, mode)
path: 要打开的文件、设备的路径
oflag:
(1)必选:O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(读写)
(2)可选:O_APPEND 末尾写入
O_CREAT 文件不存在则创建它,使用该选项需要添加第三个参数;
O_TRUNC 如果文件存在,而且为只写或读写成功打开,则将其长度截取为0;相当于清空文件夹。
(3)mode:这个是指文件的权限,对应所有者、group、other的权限,对于普通文件一般为读写即可。
fd = open(“test.txt”, O_RDWR | O_CREAT | O_TRUNC ,0666)
fd = open(“test.txt”, O_RDWR | O_TRUNC )
(4)fd为文件描述符,相当于操作该文件对象的一个编号。
2、create()
int creat(const char *path, mode_t mode);
此函数用来创建一个新文件并返回其fd。
它等价于 open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);
3、write()
ssize_t write(int fd, const void *buf, size_t nbytes);
(1)fd:写入数据的文件对象
(2)buf:将buf中的数据写入文件中。
(3)nbytes:指定要写入数据的大小,一般和读取的字符大小一致。
(4)返回值:如果 >0 则为写入字符个数,如果 <0 则写入出错。
4、read()
ssize_t read(int fd, const void *buf, size_t nbytes);
(1)fd:读出数据的文件对象
(2)buf:将数据读入到buf中。
(3)nbytes:指定要读取数据的大小,一般和buf大小的一致。
(4)返回值:如果 >0 则为读出字符个数,如果 <0 则读出出错。
5、close()
int close(int fd);
该函数用来关闭一个打开的文件描述符,关闭一个文件时还会释放该进程加在该文件上的所有记录锁。当一个进程终止时,内核将会自动关闭它所有打开的文件。
1、lseek()函数
off_t lseek(int fd, off_t offset, int whence);
通过lseek()这个函数我们可以调整文件偏移量的地址。因为在我们打开一个文件进行写入数据时,光标是跑到最后一个字符的后面的,如果这时候对文件的信息进行读取,那么它就会从光标处开始读取,这样光标后面是没有数据可读的,最后读取的数据为0,所以我们要进行文件偏移量设置。当然,对于未初始的buf,我们也应该使用memset()进行清空数组空间。
SEEK_SET 文件头
SEEK_CUR 当前位置
SEEK_END 文件尾
lseek(fd, 0, SEEK_SET); 将文件偏移量设置到了文件开始的第一个字节上;
lseek(fd, 0, SEEK_END); 将文件偏移量设置到文件最后一个字节上;
lseek(fd, -1, SEEK_END); 将文件偏移量设置到文件最后的倒数第一个字节上
#include
#include
#include
#include
#include
#include
#include
#define BUFSIZE 1024
#define str "hello world\n"
int main(int argc, char * argv[])
{
int fd = -1;
int rv = -1;
char buf[BUFSIZE];
fd = open("test.txt", O_RDWR | O_CREAT | O_TRUNC, 0666);
if(fd < 0)
{
printf("open the file failure : %s ", strerror(errno));
return -1;
}
printf("Open the file descriptor [%d] \n",fd);
if((rv = write(fd, str, strlen(str))) < 0)
{
printf("write into the file failure : %s\n", strerror(errno));
close(fd);
}
printf("Write %d bytes into the file \n", rv);
rv = -1;
memset(buf, 0, sizeof(buf));
lseek(fd, 0, SEEK_SET);
if((rv = read(fd, buf, sizeof(buf))) < 0)
{
printf("read the data from file failure: %s\n", strerror(errno));
close(fd);
}
printf("read %d bytes data from file: %s\n", rv, buf);
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#define BUFSIZE 1024
int main(int argc, char *argv[])
{
int read_fd1 = -1, write_fd2 = -1;
int rv1 = -1, rv2 = -1;
char buf[BUFSIZE];
read_fd1 = open(argv[1], O_RDONLY);
write_fd2 = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, 0666);
if( read_fd1 < 0 || write_fd2 < 0 )
{
printf("open the file1 failure : %s ", strerror(errno));
return -1;
}
printf("Open the file descriptor [fd1 %s: %d] [fd2 %s: %d] \n", argv[1], read_fd1, argv[2], write_fd2 );
memset(buf, 0, sizeof(buf));
if((rv1 = read(read_fd1 , buf, sizeof(buf))) < 0)
{
printf("read the data from file failure: %s\n", strerror(errno));
close(read_fd1);
close(write_fd2);
return -2;
}
if(rv2 = write(write_fd2 , buf, rv1) < 0)
{
printf("write the data failure: %s\n", strerror(errno));
close(read_fd1);
close(write_fd2);
return -3;
}
printf("1\n");
lseek(read_fd1 , 0, SEEK_SET);
lseek(write_fd2 , 0, SEEK_SET);
while((rv1 = read(read_fd1 , buf, sizeof(buf))) != 0)
{
printf("2\n");
write(write_fd2 , buf, rv1);
}
close(read_fd1);
close(write_fd2);
return 0;
}
运行效果:
三、总结
在读取数据的时候一定要注意文件偏移量,不然要么读取数据不全、要么读取不了数据,另外一个需要注意的就是,在每一次对文件操作完成之后,一定要关闭打开的文件描述符,因为假如工程量很大,需要不断地创建文件描述符在,这时候就导致溢出,fd最大可为1024个。有不足之处请各位大佬在评论区留言,谢谢。