一、文件编程概述
之前在windows中对文件的操作是:打开文档——>编辑文档——>保存文档——>关闭文档
我们的Linux文件编程主要是利用代码对文件进行操作:文件创建、打开、编辑等自动化执行等
在Linux我们要使用编程调用api函数的方式进行文档的编辑:
打开:open 读写:write/read 光标定位:lseek 关闭:close
二、文件打开与创建
2.1 文件打开创建函数open原型和头文件:
/*
Linux下:man 2 open可以查看对应手册
*/
#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);
int creat(const char *pathname, mode_t mode);
返回值 文件描述符
pathname (含路径,缺省为当前路径)
flags 权限 O_RDONLY:只读打开 O_WRONLY:只写打开 O_RDWR:可读可写打开
mode 权限模式
1.可读: r 4
2.可写: w 2
3.可执行 x 1
0600:6代表4+2(可读可写)
2.2 open函数打开一个文件:
-
利用open函数打开file1文件,如果文件存在则返回3,否则返回-1
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
fd = open("./file1",O_RDWR);
printf("fd = %d\n",fd);
return 0;
}
我们刚开始touch了一个file1文件,用open函数可以打开这个文件,返回3
我们rm删除了file1文件,用open函数打开这个文件就失败了,返回-1
2.3 open函数打开文件失败创建一个文件:
-
使用open函数打开file1文件失败后,就创建一个file1文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
fd = open("./file1",O_RDWR); //使用open函数打开file1文件
if(fd == -1){ //如果打开失败
printf("file1 no failed\n"); //输出文件1号失败
fd = open("./file1",O_RDWR|O_CREAT,0600); //文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
if(fd > 0){
printf("create file1 success!\n"); //若文件描述符>0则代表创建文件成功!
}
}
return 0;
}
最终我们可以看到创建file1文件成功!
//我们创建的file1文件权限为:可读可写
查看文件权限指令:ls -l
r 代表“可读”
w 代表“可写”
x 代表“可执行”
mode 权限模式
1.可读: r 4
2.可写: w 2
3.可执行 x 1
0600:6代表4+2(可读可写)
2.4 查看文件是否存在:
/*O_EXCL如果同时指定了O_CREAT,而文件已经存在,那么打开文件失败*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
fd = open("./file1",O_RDWR|O_CREAT|O_EXCL,0600);
if(fd == -1){ //如果O_EXCL和O_CREAT同时使用时,文件已经存在就返回-1代表文件存在
printf("file cunZai\n");
}
return 0;
}
2.5 每次写内容都到文件的尾部:
当前我们file1文件中的内容是:
如果直接往里面添加内容会出现错误,会从头开始添加,我们不希望破坏之前的内容,我们可以在open函数的可读可写权限后面或上O_APPEND
/*O_APPEND 每次写时都加到文件的尾端*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd;
char *buf = "chenlichen handsome";
fd = open("./file1",O_RDWR|O_APPEND); //添加O_APPEND后写入的内容就会从file1文件的尾部添加
printf("open susceess:fd = %d\n",fd);
//size_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,buf,strlen(buf)); //将buf中的内容写入到fd对应的文件中
if(n_write != -1){ //如果函数返回值不是-1代表写入成功
printf("success write %d byte to file1\n",n_write); //输出写入到file1文件中多少个自己
}
close(fd); //关闭刚写入的文件
return 0;
}
2.6 O_TRUNC打开已有内容的文件并删除所有内容:
当前我们file1文件中的内容是:
O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd;
char *buf = "test";
fd = open("./file1",O_RDWR|O_TRUNC); //O_TRUNC打开已有内容的文件并删除所有内容
printf("open susceess:fd = %d\n",fd);
//size_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,buf,strlen(buf)); //将buf中的内容写入到fd对应的文件中
if(n_write != -1){ //如果函数返回值不是-1代表写入成功
printf("success write %d byte to file1\n",n_write); //输出写入到file1文件中多少个自己
}
close(fd); //关闭刚写入的文件
return 0;
}
我们可以看到使用O_TRUNC打开已有内容的文件,会将文件中的内容全部删除,我们又重新写入了test内容
2.7 文件创建creat函数原型和头文件:
/*
Linux下:man creat可以查看对应手册
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int creat(const char *pathname, mode_t mode);
返回值 文件描述符
pathname 要创建的文件名(含路径、缺省为当前路径)
mode_t mode 创建模式
宏表示 数字
1.S_IRUSR 4 可读
2.S_IWUSR 5 可写
3.S_IXUSR 1 可执行
4.S_IRWXU 7 可读、可写、可执行
2.8 使用creat函数创建一个文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd;
fd = creat("/home/CLC/file1",S_IRWXU); //使用creat函数在绝对路径下创建了file1文件,权限为可读、可写、可执行
printf("creat file:fd = %d\n",fd); //文件描述符
return 0;
}
三、文件写入操作编程
3.1 文件写入函数write和文件关闭函数close原型和头文件:
/*
Linux下:man 2 write可以查看对应手册
*/
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
int fd 写入到刚打开的文件中
const void *buf 无符号类型的字符缓冲区
size_t count 写入的字节大小
ssize_t 若成功写入文件,函数返回值为写入字节个数,若失败,返回-1。
/*
Linux下:man 2 close可以查看对应手册
*/
#include <unistd.h>
int close(int fd);
int fd 关闭刚写入的文件,一般在写入文件后执行文件的关闭
3.2 对文件写入内容:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int fd;
char *buf = "chenlichen handsome";
fd = open("./file1",O_RDWR); //使用open函数打开file1文件
if(fd == -1){ //如果打开失败
printf("file1 no failed\n"); //输出文件1号失败
fd = open("./file1",O_RDWR|O_CREAT,0600); //文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
if(fd > 0){
printf("create file1 success!\n"); //若文件描述符>0则代表创建文件成功!
}
}
printf("open susceess : fd = %d\n",fd); //输出创建或者打开的文件的文件描述符
//ssize_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,buf,strlen(buf)); //将buf中的内容写入到fd对应的文件中
if(n_write != -1){ //如果函数返回值不是-1代表写入成功
printf("success write %d byte to file1\n",n_write); //输出写入到file1文件中多少个自己
}
close(fd); //关闭刚写入的文件
return 0;
}
通过open函数成功打开了file1文件,并将内容chenlichen handsom(19个字节)写入到文件中
通过open函数打开file1文件失败后,创建了一个file1文件,创建的文件文件描述符是3,并将内容chenlichen handsome(19个字节)写入到文件中
四、文件读取操作编程
4.1 文件读取函数read函数原型和头文件:
/*
Linux下:man 2 read可以查看对应手册
*/
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
fd 文件描述符
void *buf 待读入缓冲区
size_t count 读出字节个数
ssize_t 若成功读取文件,函数返回值为读出字节个数,若失败,返回-1
read函数作用:从fd指向的文件读取count个字节的数据放到buf缓冲区里面
4.2 使用read函数读取文件中的内容:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd;
char *buf = "chenlichen handsome";
fd = open("./file1",O_RDWR); //使用open函数打开file1文件
if(fd == -1){ //如果打开失败
printf("file1 no failed\n"); //输出文件1号失败
fd = open("./file1",O_RDWR|O_CREAT,0600); //文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
if(fd > 0){
printf("create file1 success!\n"); //若文件描述符>0则代表创建文件成功!
}
}
printf("open susceess : fd = %d\n",fd); //输出创建或者打开的文件的文件描述符
//ssize_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,buf,strlen(buf)); //将buf中的内容写入到fd对应的文件中
if(n_write != -1){ //如果函数返回值不是-1代表写入成功
printf("success write %d byte to file1\n",n_write); //输出写入到file1文件中多少个自己
}
char *readBuf;
readBuf = (char *)malloc(sizeof(char) * n_write + 1); //写入了多少个字节就开辟多少个字节的空间
//ssize_t read(int fd, void *buf, size_t count);
int n_read = read(fd,readBuf,n_write); //从fd指向的文件读取n_write个字节的数据放到readBuf缓冲区里面
printf("read %d,context:%s\n",n_read,readBuf); //读取了多少字节,读取到文件中的内容
close(fd); //关闭文件
return 0;
}
我们可以看到我们向file1文件中写入了chenlichen handsome,但是使用read函数读取文件中的内容到readBuf中,但是读取到的字节为0,并且也没有读取到内容,这是因为我们往file1文件中写入了chenlichen handsome后,文件中光标的位置已经到了尾巴,如果想要读取成功需要将光标移动到头,后面再使用此方法
这次我们这样:把写入内容到file1文件中后把文件关闭,读取的时候再重新的打开
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd;
char *buf = "chenlichen handsome";
fd = open("./file1",O_RDWR); //使用open函数打开file1文件
if(fd == -1){ //如果打开失败
printf("file1 no failed\n"); //输出文件1号失败
fd = open("./file1",O_RDWR|O_CREAT,0600); //文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
if(fd > 0){
printf("create file1 success!\n"); //若文件描述符>0则代表创建文件成功!
}
}
printf("open susceess : fd = %d\n",fd); //输出创建或者打开的文件的文件描述符
//ssize_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,buf,strlen(buf)); //将buf中的内容写入到fd对应的文件中
if(n_write != -1){ //如果函数返回值不是-1代表写入成功
printf("success write %d byte to file1\n",n_write); //输出写入到file1文件中多少个自己
}
close(fd); //往file1文件中写入内容成功后“关闭文件”
fd = open("./file1",O_RDWR); //读取前重新打开,目的就是让光标回到头
char *readBuf;
readBuf = (char *)malloc(sizeof(char) * n_write + 1); //写入了多少个字节就开辟多少个字节的空间
//ssize_t read(int fd, void *buf, size_t count);
int n_read = read(fd,readBuf,n_write); //从fd指向的文件读取n_write个字节的数据放到readBuf缓冲区里面
printf("read %d,context:%s\n",n_read,readBuf); //读取了多少字节,读取到文件中的内容
close(fd);
return 0;
}
使用这种方式让光标回到头还是比较“蠢”的,关于光标回到头还是有更好的方式的,下次再解决!
五、文件光标移动操作
5.1 文件光标移动函数lseek函数原型和头文件:
/*
Linux下:man 2 lseek可以查看对应手册
*/
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
off_t 若成功移动光标,函数返回值为光标移动个数,若失败,返回-1
fd 文件描述符
off_t offset 针对whence光标偏移个数
int whence 光标的绝对位置
1.SEEK_SET 文件头 The offset is set to offset bytes.
2.SEEK_CUR 光标当前位置 The offset is set to its current location plus offset bytes.
3.SEEK_END 文件内容末尾 The offset is set to the size of the file plus offset bytes.
lseek函数作用:将文件读写指针相对whence移动offset个字节
5.2 使用lseek函数对文件进行操作:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd;
char *buf = "chenlichen handsome";
fd = open("./file1",O_RDWR); //使用open函数打开file1文件
if(fd == -1){ //如果打开失败
printf("file1 no failed\n"); //输出文件1号失败
fd = open("./file1",O_RDWR|O_CREAT,0600); //文件不存在则创建它,需要同时说明第三个参数mode,权限为可读可写
if(fd > 0){
printf("create file1 success!\n"); //若文件描述符>0则代表创建文件成功!
}
}
printf("open susceess : fd = %d\n",fd); //输出创建或者打开的文件的文件描述符
/*ssize_t write(int fd, const void *buf, size_t count); write函数原型*/
int n_write = write(fd,buf,strlen(buf)); //将buf中的内容写入到fd对应的文件中
if(n_write != -1){ //如果函数返回值不是-1代表写入成功
printf("success write %d byte to file1\n",n_write); //输出写入到file1文件中多少个自己
}
char *readBuf;
readBuf = (char *)malloc(sizeof(char) * n_write + 1); //写入了多少个字节就开辟多少个字节的空间
/*off_t lseek(int fd, off_t offset, int whence); lseek函数原型*/
lseek(fd,0, SEEK_SET); //将光标移动到头
// lseek(fd,-19, SEEK_END); //将光标从尾巴移动到头
// lseek(fd,-19, SEEK_CUR); //将光标从当前位置移动到头
/*ssize_t read(int fd, void *buf, size_t count); read函数原型*/
int n_read = read(fd,readBuf,n_write); //从fd指向的文件读取n_write个字节的数据放到readBuf缓冲区里面
printf("read %d,context:%s\n",n_read,readBuf); //读取了多少字节,读取到文件中的内容
close(fd);
return 0;
}
针对于我们读取文件时遇到的问题,我们通过lseek函数将光标移动到头,成功读取到file1文件中的内容
5.3 使用lseek函数可以的巧妙的计算文件大小:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int fd;
fd = open("./file1",O_RDWR); //使用open函数打开file1文件
int filesize = lseek(fd, 0, SEEK_END); //使用lseek函数计算file1文件的大小
printf("file's size is :%d\n",filesize); //打印输出
close(fd); //关闭文件
return 0;
}
我们使用ls -l指令可以查看到file1文件的大小是19个字节,我们调用lseek函数可以巧妙的查看文件的大小
六、文件操作原理简述
文件编程的一般步骤:
打开/创建文件 − > ->−> 读取文件/写入文件 − > ->−> 关闭文件
Linux文件管理简述:
七、文件编程练手(一)实现copy指令(面试)
7.1 copy指令在Linux下的应用:
copy 指令在Linux系统是一个常用的指令,就是这样用:
cp demo4.c demo13.c
其中 copy是指令,demo4.c是源文件,demo13.c是目标文件,下面我们就来编程
7.2 main函数的参数:
/*main函数参数功能*/
int main(int argc,char **argv)
int argc argc 表示运行C文件参数的个数
char **argv argv是字符数组指针,每个指针都是一个数组,在这里表示每个参数的内容
下面我们验证一下:
#include <stdio.h>
int main(int argc, char **argv)
{
printf("total params: %d\n",argc); //C文件参数个数有三个
printf("No.1 params: %s\n",argv[0]); //第一个
printf("No.2 params: %s\n",argv[1]); //第二个
printf("No.3 params: %s\n",argv[2]); //第三个
return 0;
}
我们搞清楚main函数的参数是:./a.out src des
这样我们就可以把文件名传进去进行响应的拷贝操作如:cp demo13.c new.c
7.3 文件编程实现copy指令:
用文件编程实现copy指令的编程思路:
-
打开源文件src.c
-
读源文件src.c到buf
-
打开/创建目标文件des.c
-
将buf写入到目标文件des.c
-
关闭两个文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
int fdSrc;
int fdDes;
char *readBuf = NULL;
if(argc != 3){ //判断C文件参数是不是有三个,如果不是程序退出
printf("param error\n");
exit(-1);
}
fdSrc = open(argv[1],O_RDWR); //打开源文件demo13.c
int size = lseek(fdSrc,0, SEEK_END); //计算源文件有多少个字节
lseek(fdSrc, 0, SEEK_SET); //让源文件光标回到头
readBuf = (char *)malloc(sizeof(char) * size + 8); //动态开辟readBuf的内存空间
int n_read = read(fdSrc,readBuf,size); //把源文件的size个字节的内容读取到readBuf里面
fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600); //打开目标文件new.c,如果打开失败就创建目标文件new.c
//如果存在目标文件,就把文件中的内容全部干掉,否则会出错
int n_write = write(fdDes,readBuf,strlen(readBuf)); //将readBuf里面的内容写入到目标文件new.c中
close(fdSrc); //关闭源文件
close(fdDes); //关闭目标文件
return 0;
}
我们可以看到打开我们cp的new.c文件,和源文件demo13.c内容是一模一样的,这样就使用文件编程实现了copy指令
八、文件编程练手(二)修改程序的配置文件(工作常用)
在工作中我们经常会遇到修改配置文件相关的问题,比如以下配置文件:
我们要把LENG修改成5,我们该怎么办呢?
8.1 使用文件编程修改配置文件的指定内容:
编程思路:
-
打开配置文件
-
读出配置文件内容
-
找到LENG字符串的起始位置
-
偏移LENG的长度,偏移到数据位置
-
更改数据位置的值
-
把读出的内容重新写入配置文件
-
关闭文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
int fdSrc;
char *readBuf = NULL;
if(argc != 2){ //判断C文件参数是不是有两个,如果不是程序退出
printf("param error\n");
exit(-1);
}
fdSrc = open(argv[1],O_RDWR); //打开配置文件
int size = lseek(fdSrc,0, SEEK_END); //计算配置文件有多少个字节
lseek(fdSrc, 0, SEEK_SET); //让配置文件光标回到头
readBuf = (char *)malloc(sizeof(char) * size + 8); //动态开辟readBuf的内存空间
int n_read = read(fdSrc,readBuf,size); //把配置文件的size个字节的内容读取到readBuf里面
//char *strstr(const char *haystack, const char *needle);
char *p = strstr(readBuf,"LENG="); //字符串查找函数,返回值为要查找的字符串的第一个字符的指 针,第一个参数为待查找的原始字符串,第二个参数为要查找的内容
p = p + strlen("LENG="); //偏移LENG的长度,偏移到数据位置
*p = '5'; //更改数据位置的值
lseek(fdSrc, 0, SEEK_SET); //让配置文件光标回到头
int n_write = write(fdSrc,readBuf,strlen(readBuf)); //把读出的内容重新写入配置文件
close(fdSrc); //关闭配置文件
return 0;
}
8.2 字符串比较函数strstr原型和头文件:
/*
Linux下 man strstr可以查看对应手册
*/
#include <string.h>
char *strstr(const char *haystack, const char *needle); //字符串查找函数
char * 返回值为要查找的字符串的第一个字符的指针
const char *haystack 待查找的原始字符串
const char *needle 为要查找的内容
九、写一个整数、结构体和结构体数组到文件
前面我们都是写字符串到文件中,那可不可以写入整数或者结构体呢?
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
这两个是写and读的函数原型,我们可以发现第二个参数都是:void *buf
这样我们即可以写入字符串,又可以将整数或者结构体的地址传递过去,进行读和写
9.1 写一个整数到文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd;
int data = 100;
int data2;
fd = open("./file1",O_RDWR); //打开file1文件
//size_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,&data,sizeof(int)); //写整数100到文件
lseek(fd, 0, SEEK_SET); //写完之后,光标回到文件头
//ssize_t read(int fd, void *buf, size_t count);
int n_read = read(fd,&data2,sizeof(data2)); //把file1文件中的内容读4个字节到data2中
printf("read %d\n",data2); //输出读取的结果
close(fd);
return 0;
}
成功向file1文件中写入了一个整数,并且把文件中的整数读取到了data2中,最终输出结果
打开我们发现是乱码的,是因为整数在文件中的体现方式并不是我们肉眼看到的那样,只要程序可以成功写入/读取即可
9.2 写一个结构体到文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
struct Test
{
int idata;
char cdata;
};
int main()
{
int fd;
struct Test t1 = {100,'#'}; //定义一个结构体变量并赋初值
struct Test t2;
fd = open("./file1",O_RDWR); //打开file1文件
//size_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,&t1,sizeof(struct Test)); //写一个结构体到文件中
lseek(fd, 0, SEEK_SET); //写完之后,光标回到文件头
//ssize_t read(int fd, void *buf, size_t count);
int n_read = read(fd,&t2,sizeof(struct Test)); //读文件中的结构体到t2中
printf("read t2 = %d,%c\n",t2.idata,t2.cdata); //输出读取的结果
close(fd); //关闭文件
return 0;
}
成功向file1文件中写入了一个结构体,并且把文件中的结构体读取到了t2中,最终输出结果
9.3 写一个结构体数组到文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
struct Test
{
int idata;
char cdata;
};
int main()
{
int fd;
int i;
struct Test arr1[2] = { //定义一个arr1结构体数组并初始化
{100,'#'},
{200,'$'}
};
struct Test arr2[2]; //定义一个arr2结构体数组并初始化
int arr1Size = sizeof(arr1) / sizeof(arr1[0]); //计算arr1结构体数组的元素个数
int arr2Size = sizeof(arr2) / sizeof(arr2[0]); //计算arr2结构体数组的元素个数
fd = open("./file1",O_RDWR); //打开file1文件
//size_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,&arr1,sizeof(struct Test) * arr1Size); //把arr1结构体数组写到文件中
lseek(fd, 0, SEEK_SET); //写完之后,光标回到文件头
//ssize_t read(int fd, void *buf, size_t count);
int n_read = read(fd,&arr2,sizeof(struct Test) * arr2Size); //把写入文件中的结构体数组读取到arr2中
for(i=0; i<2; i++){
printf("read arr2 = %d,%c\n",arr2[i].idata,arr2[i].cdata); //输出读取到的值
}
close(fd); //关闭文件
return 0;
}
成功向file1文件中写入了一个结构体数组,并且把文件中的结构体数组读取到了arr2中,最终输出结果
十、标准C库对文件操作引入
fopen与open的区别
1、来源不同 open是unix系统调用函数(包括Linux),返回的是文件描述符,它是文件描述符表里的索引。 fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调不同的内核api,返回的是一个指向文件结构的指针。
2、移植性 从来源看,fopen是C标准函数,因此拥有良好的移植性,而open是unix系统调用,移植性有限,如windows下相似的功能使用api函数CreatFile。
3、使用范围 open返回文件描述符,而文件描述符是unnix系统下的重要概念,unix下的一切设备都是文件的形式操作,如网络套接字、硬件设备等、当然包括操作普通正规文件(Regular File) Fopen是从来操纵普通正规文件(Regular File)的
4、 文件IO层次 如果从文件IO的角度来看,open属于低级IO函数,fopen属于高级IO函数,低级和高级的简单区分标准是:谁离系统内核更近,低级文件IO运行在内核态、高级文件IO运行在用户态。
5、 缓冲区 open没缓冲区(多次在用户态和内核态切换,执行速度慢,效率低),fopen有缓冲区(在缓冲区读写后一次性写入文件,执行速度快,效率高)
更多详细介绍观看此路径https://www.cnblogs.com/NickyYe/p/5497659.html,念这些啰里啰唆的概念不是我的风格!!!
主打的就是一个拽!!!
十一、标准C库打开创建文件读写关闭文件和光标移动
11.1 打开创建文件函数fopen函数原型和头文件:
/*
Linux下 man fopen查看手册
*/
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
FILE * 返回值并不是文件描述符,若失败返回NULL,若操作成功返回FILE指针
const char *path 文件路径
const char *mode 打开方式
mode 打开模式:
r 只读方式打开一个文本文件
rb 只读方式打开一个二进制文件
w 只写方式打开一个文本文件
wb 只写方式打开一个二进制文件
a 追加方式打开一个文本文件
ab 追加方式打开一个二进制文件
r+ 可读可写方式打开一个文本文件
rb+ 可读可写方式打开一个二进制文件
w+ 可读可写方式创建一个文本文件
wb+ 可读可写方式生成一个二进制文件
a+ 可读可写追加方式打开一个文本文件
ab+ 可读可写方式追加一个二进制文件
11.2 文件写入函数fwrite函数原型和头文件:
/*
Linux下 man fwrite查看手册
*/
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
size_t 返回值若成功写入文件,函数返回值为写入次数(函数第三个参数),若失败,返回非写入字节个数或0
const void *ptr 是写的数据存放的缓冲区
size_t size 每次写的字节数
size_t nmemb 写入数据的次数
FILE *stream 表示要写入哪个文件(已打开文件的指针,一般就是fopen的返回值)
11.3 文件读取函数fread函数原型和头文件:
/*
Linux下 man fread查看手册
*/
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
size_t 若成功读出文件,函数返回值为读取总共字节个数(函数第三个参数),若失败,返回非写入字节个数或0
void *ptr 读的数据存放的缓冲区
size_t size 每次读的字节数
size_t nmemb 读取数据的次数
FILE *stream 表示要读取哪个文件(已打开文件的指针,一般就是fopen的返回值)
11.4 文件光标移动函数fseek函数原型和头文件:
/*
Linux下 man fseek查看手册
*/
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
int 函数返回值,若成功移动光标,函数返回值为0,若失败,返回-1
FILE *stream 要移动光标的文件
long offset 针对whence光标偏移个数
int whence 光标的绝对位置
1.SEEK_SET 文件头 The offset is set to offset bytes.
2.SEEK_CUR 光标当前位置 The offset is set to its current location plus offset bytes.
3.SEEK_END 文件内容末尾 The offset is set to the size of the file plus offset bytes.
11.5 文件关闭函数fclose函数原型和头文件:
/*
Linux下 man fclose查看手册
*/
#include <stdio.h>
int fclose(FILE *fp);
int 函数返回值,成功关闭文件则返回0,非则返回EOF
FILE *fp 表示要关闭哪个文件(已打开文件的指针,一般就是fopen的返回值)
11.6 标准C库对文件打开写入读取关闭编程实现:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
char *str = "chenlichen handsome";
char readBuf[128] = {0};
//FILE *fopen(const char *path, const char *mode);
fp = fopen("./chen.txt","w+"); //可读可写方式创建一个文本文档并打开,文件名chen.txt
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
fwrite(str,sizeof(char),strlen(str),fp); //把str中的内容写入到文件中,一次写1个字节,写strlen(str)次
//fwrite(str,sizeof(char)*strlen(str),1,fp); //把str中的内容写入到文件中,一次把所有内容写入到文件中
//int fseek(FILE *stream, long offset, int whence);
fseek(fp,0,SEEK_SET); //写完之后文件中的光标回到头
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread(readBuf,sizeof(char),strlen(str),fp); //把文件中的内容读取到readBuf中,一次读一个字节,读strlen(str)次
//fread(readBuf,sizeof(char),strlen(str),fp); //把文件中的内容读取到readBuf中,一次把所有内容全部读出
printf("read data: %s\n",readBuf); //输出从文件中读取到readBuf的内容
fclose(fp); //关闭文件
return 0;
}
十二、标准C库写入结构体到文件
12.1 写一个整数到文件:
#include <stdio.h>
int main()
{
FILE *fp;
int data = 100;
int data2;
fp = fopen("./file1","w+"); //打开file1文件,没有的话就创建
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
fwrite(&data,sizeof(int),1,fp); //写一个整数到文件中
fseek(fp, 0, SEEK_SET); //写完之后,光标回到文件头
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread(&data2,sizeof(int),1,fp); //把文件中的整数读取到data2中
printf("read %d\n",data2); //输出读取到的内容
fclose(fp); //关闭文件
return 0;
}
12.2 写一个结构体到文件:
#include <stdio.h>
struct Test
{
int idata;
char cdata;
};
int main()
{
FILE *fp;
struct Test t1 = {100,'#'}; //定义一个结构体变量并赋值
struct Test t2;
fp = fopen("./file1","w+"); //打开file1,如果没有就创建
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
fwrite(&t1,sizeof(struct Test),1,fp); //将结构体写到文件中
fseek(fp, 0, SEEK_SET); //写完之后,光标回到头
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread(&t2,sizeof(struct Test),1,fp); //把文件中的结构体读取到t2中
printf("read t2 = %d,%c\n",t2.idata,t2.cdata); //输出读取的结果
fclose(fp); //关闭文件
return 0;
}
12.3 写一个结构体数组到文件:
#include <stdio.h>
struct Test
{
int idata;
char cdata;
};
int main()
{
FILE *fp;
int i;
struct Test arr1[2] = { //定义一个结构体数组并初始化
{100,'#'},
{200,'$'}
};
struct Test arr2[2];
int arr1Size = sizeof(arr1) / sizeof(arr1[0]); //计算arr1的元素个数
int arr2Size = sizeof(arr2) / sizeof(arr2[0]); //计算arr2的元素个数
fp = fopen("./file1","w+"); //打开file1文件,没有就创建
//size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
fwrite(&arr1,sizeof(struct Test)*arr1Size,1,fp); //把arr1结构体数组写入到文件中
fseek(fp, 0, SEEK_SET); //写完之后,光标回到头
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread(&arr2,sizeof(struct Test)*arr2Size,1,fp); //把文件中的结构体数组读取到arr2中
for(i=0; i<2; i++){
printf("read arr2 = %d,%c\n",arr2[i].idata,arr2[i].cdata); //输出读取到的结构体数组
}
fclose(fp); //关闭文件
return 0;
}
十三、文件其它函数讲解及文件收尾
13.1 文件写入字符函数fputc函数原型和头文件:
/*
Linux下 man fputc查看手册
*/
#include <stdio.h>
int fputc(int c, FILE *stream);
int 函数返回值,若成功写入文件,函数返回值为写入文件的字符的ASCII码值,若出错,返回EOF(-1)
int c 要写入的字符
FILE *stream 表示要写入哪个文件(已打开文件的指针,一般就是fopen的返回值)
13.2 使用fputc函数写一个字符到文件:
#include <stdio.h>
int main()
{
FILE *fp;
char cdata = '#'; //要写入的内容
fp = fopen("test.txt","w+"); //打开file1文件,如果没有就创建
fputc(cdata,fp); //写字符到file1文件
fclose(fp); //关闭文件
return 0;
}
13.3 使用fputc函数写多个字符到文件:
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
int i;
char *str = "chenlichen handsome"; //定义一个字符串
char readBuf[128] = {0};
int len = strlen(str); //计算字符串的长度
fp = fopen("test.txt","w+"); //打开file1文件,如果没有就创建
for(i=0; i<len; i++){ //使用for循环一个一个的将字符串中的字符写入到文件中
fputc(*str,fp);
str++; //指针偏移
}
//int fseek(FILE *stream, long offset, int whence);
fseek(fp,0,SEEK_SET); //让文件中光标回到头
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread(readBuf,sizeof(char)*len,1,fp); //将文件中的内容读取到readBuf里面
printf("read %s\n",readBuf); //输出读取到的内容
fclose(fp); //关闭文件
return 0;
}
13.4 文件读取字符函数fgetc函数原型和头文件:
/*
Linux下 man fgetc查看手册
*/
#include <stdio.h>
int fgetc(FILE *stream);
int 函数返回值,若成功读出文件,函数返回值为读出文件的内容,若出错或读到末尾,返回EOF(-1)
FILE *stream 表示要读取哪个文件(已打开文件的指针,一般就是fopen的返回值)
13.5 文件尾巴检测函数feof函数原型和头文件:
/*
Linux下 man feof查看手册
*/
#include <stdio.h>
int feof(FILE *stream);
int 函数返回值,若到文件末尾,函数返回值为非0,若不到末尾,返回0
FILE *stream 表示要判断的文件
13.6 使用feof函数检测是否到文件尾部并使用fgetc函数读出文件内容:
#include <stdio.h>
int main()
{
FILE *fp;
char c;
fp = fopen("./test.txt","r"); //只读方式打开当前路径的test.txt文件
while(!feof(fp)){ //判断是否到文件尾部
c = fgetc(fp); //没有到文件尾部就一个字符一个字符的读出文件的内容
printf("%c",c); //读一次输出一次
}
fclose(fp); //关闭文件
return 0;
}
-
Linux系统一切皆文件文件系统(文件夹 /文件 ) 硬件设备 管道 数据库 Socket等,文件还是非常重要的,文件的操作就先到这里!