第8课-系统调用方式文件编程
8.1核心理论-文件描述符
在中国,每一个成年的公民都会有一个身份证编号,它的本质就是一个数字,我们可以利用这个数字来标记这个公民。在Linux系统中,所有打开的文件也对应一个数字,这个数字由系统来分配,我们称之为:文件描述符。
8.2 函数学习
用man+文件名的方式查看函数的用法。
1.打开文件
(1)函数名
open
(2)函数原形
int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
(3)函数功能
打开或者创建一个文件
(4)所属头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcbtl.h>
(5)返回值
成功:文件描述符;失败:-1.
(6)参数说明
pathname:要打开的文件名(含路径)
flags:文件打开的标志,它只能使用O_RDONLY,O_WDONLY,O_RDWR中的一个。
-O_APPEND:已追加的方式打开文件
-O_CREAT:当文件不存在的时候,创建这个文件
mode:一定是在flags中使用了O_CREAT标志,mode记录待创建文件的访问权限。
(7)测试文件
不用新创建文件的:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
void main()
{
int fd;
fd = open("/home/text.c",O_RDWR);
if(fd<0)
printf("open file fail! ");
}
该文件在编译的时候会出,printf不相容的警报,忽略即可。
新创建文件的:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
void main()
{
int fd;
fd = open("/home/text1.c",O_RDWR|O_CREAT,0755);
if(fd<0)
printf("open file fail! ");
}
- 创造文件
(1)函数名
creat
(2)函数原形
int creat(const char *pathname,mode_t mode)
(3)函数功能
创建一个文件,并且以只写的方式打开该文件。
(4)所属头文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
(5)返回值
成功:文件描述符
失败:-1
(6)参数说明
pathname:要打开的文件名(含路径)
mode:创建文件的读写权限
(7)示例程序
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
void main()
{
int fd;
fd = creat("/home/test2.c",0621);
if(fd<0)
printf("fail ");
}
- 关闭文件
(1) 函数名
close
(2)函数原形
int close(int fd)
(3) 函数功能
关闭一个打开的文件。
(4) 所属头文件
#include<unistd.h>
(5) 返回值
成功:0
失败:-1
(6)参数说明
fd:待关闭的文件描述符
(8)示例程序
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
void main()
{
int fd;
fd = open("/home/text1.c",O_RDWR|O_CREAT,0755);
if(fd<0)
printf("open file fail! ");
close(fd);
}
- 读文件
这里需要注意,我们使用man read命令的时候会发生错误,找的不是我们要找的文件。我们需要了解man命令是相当于一个菜单的,只要包含几个方面的章节(1)命令;(2)系统调用函数;(3)库函数。
当使用man read时,关键字是read。它会默认的从第一个章节里面找,若果第一个章节里面找不到才会在下面的章节里面找。可是,在第一个章节里面是有read这个关键字的,所以我们查到的不是我们要的那个属于系统调用函数的关键字。我们使用man 2 read查找就好。
(1) 函数名
read
(2)函数原形
ssize_t read(int fd,void *buf,size_t count);
(3)函数功能
从一个打开的文件中读取数据
(4)所属头文件
#include<unistd.h>
(5)返回值
成功:返回读取的字节数
失败:-1
(6)参数说明
fd:打开的文件描述符(要读取的数据的文件描述符)
count:希望读取的字节数
buf:指向读取来的数据存到buf指向非空间
(7)范例程序
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
void main()
{
int fd;
char buf[10];
fd = open("/home/text1.c",O_RDWR|O_CREAT,0755);
if(fd<0)
printf("open file fail! ");
read(fd,buf,5);
buf[5] = " ";
printf("buf is %s ",buf);
close(fd);
}
- 写文件
(1) 函数名
write
(2)函数原形
ssize_t write(int fd,void *buf,size_t count);
(3)函数功能
向一个打开的文件中写入数据
(4)所属头文件
#include<unistd.h>
(5)返回值
成功:返回写入到文件里面的字节数
失败:-1
(6)参数说明
fd:写入的文件描述符(要写入的数据的文件描述符)
count:希望写入的字节数
buf:buf指向非空间的数据写入到文件
(8)范例程序
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
void main()
{
int fd;
char *buf = "987654321";
fd = open("/home/text1.c",O_RDWR|O_CREAT,0755);
if(fd<0)
printf("open file fail! ");
write(fd,buf,10);
printf("buf is %s ",buf);
close(fd);
}
- 定位文件
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
void main()
{
int fd;
char *buf = "987654321";
char buf1[10];
fd = open("/home/text1.c",O_RDWR|O_CREAT,0755);
if(fd<0)
printf("open file fail! ");
write(fd,buf,7);
read(fd,buf1,5);
buf1[5] = " ";
printf("buf1 is %s ",buf1);
close(fd);
}
我们首先看到这个测试程序,按道理来分析,我们存入7个字节,读取5个字节,应该是不冲突额,应该能读出来98765这几个字节。但是,在操作的过程中,我们却读出来了空的内容。原因是我们在执行文件的时候,比如write函数写入7个字节,那么它的指针也是指向第七个字节后面。当执行read操作时,我们从指针的位置开始执行,自然什么也没有是空的。怎么解决这一个问题呢?我们下面介绍
(1) 函数名
lseek
(2)函数原形
off_t lseek(int fd,off_t offset,int whence);
(3)函数功能
重新定位文件的读写位置
(4)所属头文件
#include<unistd.h>
#include<sys/types.h>
(5)返回值
成功:返回移动后的文件指针距离文件头的位置
失败:-1
(6)参数说明
fd:文件描述符(指定的使我们要操作的文件)
whence:表示指针的开始位置,只能取下面的三种值。
SEEK_SET文件的开头加上offset(正的)
SEEK_CUR当前的指针加上offset(可正可负)的位置
SEEK_END从文件的末尾加上offset(负的)
offset:指针将要加的数。
(7)范例程序
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
void main()
{
int fd;
char *buf = "1234567890";
char buf1[10];
fd = open("/home/text1.c",O_RDWR|O_CREAT,0755);
if(fd<0)
printf("open file fail! ");
write(fd,buf,10);
lseek(fd,0,SEEK_SET);
read(fd,buf1,5);
buf1[5] = " ";
printf("buf1 is %s ",buf1);
close(fd);
}
- 复制文件描述符
(1) 函数名
dup
(2)函数原形
int dup(int oldfd);
(3)函数功能
复制一个文件描述符
(4)所属头文件
#include<unistd.h>
(5)返回值
成功:返回新的文件描述符
失败:-1
(6)参数说明
oldfd:待复制的文件描述符
(7)范例程序
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
void main()
{
int fd;
int fd1;
char *buf = "1234567890";
char buf1[10];
fd = open("/home/text1.c",O_RDWR|O_CREAT,0755);
if(fd<0)
printf("open file fail! ");
fd1 = dup(fd);
write(fd1,buf,10);
lseek(fd1,0,SEEK_SET);
read(fd1,buf1,5);
buf1[5] = " ";
printf("buf1 is %s ",buf1);
close(fd1);
}
8.3综合实例
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
void main(int argc,char **argv)
{
int fd_s;
char buf[512];
int count = 0;
int fd_t;
//1.打开原文件
fd_s = open(argv[1],O_RDONLY);
//2.打开目标文件
fd_t = open(argv[2],O_RDWR|O_CREAT,0666);
//3.读取原文件中的数据,将读取出的原文件数据写入目标文件
while((count = read(fd_s,buf,512))>0)
write(fd_t,buf,512);
//4.关闭文件
close(fd_s);
close(fd_t);
}
当我们使用上面编辑的代码,运行./filecp t.txt s.txt时,我们会发现生成的s.txt中有许多的乱码,原因是,我们每一次都是进行512个字节的复制,当不满足512个字节的时候,我们仍然按照512个字节去复制,于是出现了问题。我们将文件进行如下的修改:
while((count = read(fd_s,buf,512))>0)
write(fd_t,buf,count);
这样我们的./filecp就可以当做cp命令来使用。