linux文件编程
1.文件打开及创建
1.1基本格式:
#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);
可新开一个窗口使用指定:man 2 open
1.2对open内参数的讲解:
const char *pathname :想要打开文件的文件名(包含路径)
int flags:权限--> O_RDONLY 只读打开 O_WRONLY 只写打开 O_RDWR 可读可写打开
mode_t mode:在flags中携带了O_CREAT权限时,mode记录待创建的文件的访问权限
mode_t mode的取值:每个数字可以取1(执行权限)、2(写权限)、4(读权限)、0(无)或者是这些值的和。
0100:可执行
0200:可写
0400:可读
0600:可读,可写 -->4+2=6
0700:可读,可写,可执行-->4+2+1=7
如果打开成功返回文件描述符fd
如果打开失败出错返回-1并设置errno
对于mode_t mode的值可采用宏(允许用一个标识符来表示一个字符串,称为宏)
宏表示 数字
S_IXUSR 1 可执行
S_IWUSR 2 可写
S_IRUSR 4 可读
S_IRWXU 7 可读、写、执行
---------------------------------------------------------------------------------------------
当我们设置了某种权限时,文件的打开之后只能按照权限来操作
以上这三个常数中应当只指定一 个。下列常数是可选择的:
O_CREAT 若文件不存在则创建它。使用此选项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限。
O_EXCL 如果同时指定了OCREAT,而文件已经存在,则出错,返回-1。
O_APPEND 每次写时都加到文件的尾端。(若不写则部分覆盖)
O_TRUNC 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0。(写入前全部删除)
1.3文件描述符(fd):
文件的描述符fd相当于文件的身份证,每一个都是独一无二的存在,不会有相同的fd值。
文件描述符是一个非负的整数,当打开一个文件或创建一个文件时,内核向进程返回一个标识该文件的整数,即fd。
注意,若文件不被创建打开(即没有载入进程),是没有文件描述符可言的。
1.4编程实战:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main()
{
int fd; //文件描述符--相当于文件的索引
//int open(const char *pathname, int flags);
fd = open("./file1",O_RDWR);//打开file1文件,并且权限是可读可写
if(fd == -1){//open函数打开文件失败(无该文件)时返回值-1
printf("open file1 failed\n");
//int open(const char *pathname, int flags, mode_t mode);
fd = open("./file1",O_RDWR|O_CREAT,0600); //创建file1文件,权限可读可写
if(fd >0){//open函数打开文件成功返回正数。
printf("creat file1 success!\n");
}
}
return 0;
}
对于权限0600的讲解 可读+可写 = 4+2
可读 | r | 4 |
可写 | w | 2 |
执行 | x | 1 |
对于文件查询可使用ls -l
可显示文件清单
2.文件写入操作编程
2.1基本格式:
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
2.2对write内部参数的讲解
int fd:文件的描述符(相当于文件的身份证)
const void *buf:待写入的缓冲区
size_t count:写入字节的数量
-------------------------------------------------------------------------------------------------------------------
write函数的返回值
成功:写入文档的字节数
失败:-1
成功时返回写的字节数,错误时返回-1
2.3编程实战:
在编程前查询write使用的函数man 2 write
#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 = "xiaoqiang jiayou";
//int open(const char *pathname, int flags);
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file1 failed\n");
//int open(const char *pathname, int flags, mode_t mode);
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd >0){
printf("creat file1 success!\n");
}
}
printf("open sucess : fd = %d\n",fd);
//ssize_t write(int fd, const void *buf, size_t count);
write(fd,buf,strlen(buf));//写入文件 buf-->fd
//int close(int fd)
close(fd);//关闭文件
return 0;
}
2.4运行结果:
/file1文件内:
3.文件读取操作
3.1基本格式:
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
在以fd为索引的文件,读取count字节放到buf中
3.2对read内部参数讲解:
int fd:文件描述符
void *buf:待读入缓存区
size_t count:读出字节个数
-------------------------------------------------------------------------------------------------------------------
read函数的返回值
成功:返回读取的字节数
出错:返回-1并设置errno
3.3编程实战:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd;
char *buf = "xiaoqiang jiayou";
//int open(const char *pathname, int flags);
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file1 failed\n");
//int open(const char *pathname, int flags, mode_t mode);
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd >0){
printf("creat file1 success!\n");
}
}
printf("open sucess : fd = %d\n",fd);
//ssize_t write(int fd, const void *buf, size_t count);
int n_write = write(fd,buf,strlen(buf));
if(n_write != -1){
printf("success write %d byte to file1\n",n_write);
}
//int close(int fd)
close(fd); //为了让光标重新回到初始处,关闭文件重新打开,该操作可在讲解光标移动的时候优化
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-->readBuf
printf("read %d,context:%s\n",n_read,readBuf);
close(fd);
return 0;
}
4.文件光标移动操作
4.1基本格式;
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
作用:将文件读写指针相对whence移动offset个字节
4.2对lseek内部参数的讲解
int fd:文件描述符
off_t offset:偏移值,对whence的偏移值,整数往后,负数往前
int whence:光标位置
---------------------------------------------------------------------------------------------------------------
用宏来表述whence:
SEEK_SET 参数 offset即为新的读写位置(文件头)
SEEK_CUR 以目前的读写位置往后增加 offset 个位移量(当前光标位置)
SEEK_END 将读写位置指向文件尾后再增加 offset个位移量(文件尾)
-----------------------------------------------------------------------------------------------------------------
使用例子:
欲将读写位置移到文件开头时: lseek(fd,0, SEEK_SET);
欲将读写位置移到文件尾时: lseek(fd,0, SEEK_END);
想要取得目前文件位置时: lseek(fd,0, SEEK_CUR);
--------------------------------------------------------------------------------------------------------------
lseek函数的返回值
成功:返回目前的读写位置, 也就是距离文件开头多少个字节.
失败:则返回-1, errno 会存放错误代码.
4.3编程实战:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd;
char *buf = "xiaoqiang jiayou!";
//int open(const char *pathname, int flags);
fd = open("./file1",O_RDWR);
if(fd == -1){
printf("open file1 failed\n");
//int open(const char *pathname, int flags, mode_t mode);
fd = open("./file1",O_RDWR|O_CREAT,0600);
if(fd >0){
printf("creat file1 success!\n");
}
}
printf("open sucess : 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){
printf("success write %d byte to file1\n",n_write);
}
char *readBuf;
readBuf = (char*)malloc(sizeof(char)*n_write + 1);
//调整光标位置
//off_t lseek(int fd, off_t offset, int whence);
//lseek(fd, 0, SEEK_SET);
lseek(fd,-n_write,SEEK_CUR);//两个方法都可以 //负数往前偏移,正数往后偏移
//ssize_t read(int fd, void *buf, size_t count);
int n_read = read(fd,readBuf,n_write);//fd-->readBuf
printf("read %d,context:%s\n",n_read,readBuf);
close(fd);
return 0;
}
4.4运行结果:
4.5利用光标移动计算文件大小
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd;
fd = open("./file1",O_RDWR);
int filesize = lseek(fd, 0, SEEK_END);//利用lseek的返回值来计算
printf("file's size is:%d\n",filesize);
close(fd);
return 0;
}
---------------------------------------------------------------------------------------------
运行结果:file's size is:18
5.文件操作原理
linux系统中:
0 | 1 | 2 |
---|---|---|
标准输入 | 标准输出 | 标准错误 |
read(0,buf,len) -- 键盘输入
write(1,buf,len)-- 输出到shell中
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd;
char readBuf[128];
int n_read = read(0,readBuf,5);
int n_write = write(1,readBuf,strlen(readBuf));
printf("\ndone!\n");
return 0;
}
运行结果:
6.文件编程–实现linux cp命令
6.1在linux中常用的的cp指令
cp src.c des.c
---------------------------------------------------------------------------------------------
demo1.c :源文件
demo2.c :目标文件
6.2main函数原形
int main(int argc,char **argv)
---------------------------------------------------------------------------------------------
argc:表示运行C文件参数的个数
argv:字符数组指针,每个指针都是一个数组,在这里表示每个参数的内容
---------------------------------------------------------------------------------------------
eg:
cp src.c des.c
cp-->agrv[0]
src.c-->argv[1]
des.c-->argc[2]
6.3对main原形的编程实战
#include <stdio.h>
int main(int argc,char **argv)
{
printf("total params:%d\n",argc);
printf("No.1 param:%s\n",argv[0]);
printf("No.2 param:%s\n",argv[1]);
printf("No.3 param:%s\n",argv[2]);
return 0;
}
运行结果:
6.4实现cp指令的编程思路
(1)打开src源文件(要被复制的文件)
(2)把src源文件的内容读入buf
(3)创建des目标文件
(4)把buf内容写入des目标文件
(5)关闭源文件与目标文件
6.5cp指令的编程实战
巧记:读入read:fdsrc–>readBuf
写出write:fddes<–readBuf
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#argc表示程序运行时发送给main函数的命令行参数的个数(包括可执行程序以及传参)。
#argv[]是字符指针数组,它的每个元素都是字符指针,指向命令行中每个参数的第一个字符。
int main(int argc, char **argv)
{
int fdSrc;
int fdDes;
char *readBuf = NULL;
if(argc != 3){
printf("param error!\n");
exit(-1);
}
//(1)打开src源文件(要被复制的文件)
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);
//(2)把src源文件的内容读入buf
int n_read = read(fdSrc, readBuf, size);
//(3)创建des目标文件
fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);
//(4)把buf内容写入des目标文件
int n_write = write(fdDes, readBuf, strlen(readBuf));
//(5)关闭源文件与目标文件
close(fdSrc);
close(fdDes);
return 0;
}
7.文件编程–修改程序的配置文件
7.1现有配置文件config.c修改其内部参数
//config.c
SPEED=3
LENG=3
SCORE=9
LEVEL=5
修改LENG的值为5
7.2编程实战
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "stdio.h"
#include <unistd.h>
#include "string.h"
#include <stdlib.h>
int main(int argc, char **argv)
{
int fdSrc;
char *readBuf = NULL;
if(argc != 2){
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);
int n_read = read(fdSrc, readBuf, size);
char *p = strstr(readBuf, "LENG=");
p = p + strlen("LENG="); //字符串查找函数,返回值为要查找的字符串的第一个字符的指针,第一个参数为待查找的原始字符串,第二个参数为要查找的内容
*p = '5';
lseek(fdSrc, 0, SEEK_SET);
int n_write = write(fdSrc, readBuf, strlen(readBuf));
close(fdSrc);
return 0;
}
运行结果:
8.写一个整数、结构体和结构体数组到文件(增加认知)
8.1基本概念
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);
//const void *buf/void *buf:都为无类型的指针,其并不只局限于字符串的写入与读出,可传地址的形式将整型数写入或读出
注意:const void *buf/void *buf:都为无类型的指针,其并不只局限于字符串的写入与读出,可传地址的形式将整型数写入或读出。
8.2编程实战
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int fd;
int data = 100;
int data2;
fd = open("./file1",O_RDWR);
int n_write = write(fd,&data,sizeof(int));//data-->fd
lseek(fd, 0, SEEK_SET);//将光标回到文件内容开头,方便后续读取等操作
int n_read = read(fd,&data2,sizeof(int));//fd-->data2
printf("read %d \n",data2);
close(fd);
return 0;
}
运行结果:
虽然最后的写入的结果并不是我们想象的样子但结果并没有错误,并不影响程序的写入和读取操作,只不过人眼看起来有点不舒服,ASCII解锁出来并不是我们想象中的样子。(思想:关键是程序读取没错误)
8.3写入一个结构体到文件中
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
struct Test
{
int idata;
char cdata;
};
int main()
{
int fd;
struct Test t1 = {100,'a'};
struct Test t2;
fd = open("./file1",O_RDWR);
int n_write = write(fd,&t1,sizeof(struct Test));//t1-->fd
lseek(fd, 0, SEEK_SET);//调整光标位置
int n_read = read(fd,&t2,sizeof(struct Test));//fd-->t2
printf("read %d %c\n",t2.idata,t2.cdata);
close(fd);
return 0;
}
8.4写入一个结构体数组到文件中
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
struct Test
{
int idata;
char cdata;
};
int main()
{
int fd;
struct Test t1[2] = {{100,'a'},{200,'b'}};
struct Test t2[2];
fd = open("./file1",O_RDWR);
int n_write = write(fd,&t1,sizeof(struct Test)*2);
lseek(fd, 0, SEEK_SET);
int n_read = read(fd,&t2,sizeof(struct Test)*2);
printf("read %d %c\n",t2[0].idata,t2[0].cdata);
printf("read %d %c\n",t2[1].idata,t2[1].cdata);
close(fd);
return 0;
}
9.标准C库对文件操作引入
fopen与open的区别
9.1、来源不同
- open是unix系统调用函数(包括Linux),返回的是文件描述符,它是文件描述符表里的索引。
- fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调不同的内核api,返回的是一个指向文件结构的指针。
9.2、移植性
- 从来源看,fopen是C标准函数,因此拥有良好的移植性,而open是unix系统调用,移植性有限,如windows下相似的功能使用api函数CreatFile
9.3、使用范围
- open返回文件描述符,而文件描述符是unnix系统下的重要概念,unix下的一切设备都是文件的形式操作,如网络套接字、硬件设备等、当然包括操作普通正规文件(Regular File)
- fopen是从来操纵普通正规文件(Regular File)的
9.4、 文件IO层次
- 如果从文件IO的角度来看,open属于低级IO函数,fopen属于高级IO函数,低级和高级的简单区分标准是:谁离系统内核更近,低级文件IO运行在内核态、高级文件IO运行在用户态。
9.5、 缓冲区
- open没缓冲区(多次在用户态和内核态切换,执行速度慢,效率低),fopen有缓冲区(在缓冲区读写后一次性写入文件,执行速度快,效率高)
10.标准C库打开创建文件读写文件光标移动
可使用man fopen
来查看具体操作
10.1基本格式-fopen
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
-------------------------------------------------------------------------------------------------------------------
const char *path:文件路径
const char *mode:打开模式
------------------------------------------------------------------------------------------------------------------------
打开模式权限:
“r” 以 只读方式打开文件,该文件必须存在。
“r+” 以可读写方式打开文件,该文件必须存在。
”rb+“ 读写打开一个 二进制文件,允许读写数据(可以任意修改),文件必须存在。
“w” 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。
“w+” 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。
“a” 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。( EOF符保留)
”a+“ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留)。
“wb” 只写打开或新建一个 二进制文件;只允许写数据(若文件存在则文件长度清为零,即该文件内容会消失)。
“wb+” 读写打开或建立一个二进制文件,允许读和写(若文件存在则文件长度清为零,即该文件内容会消失)。
10.2基本格式-fwrite
查看fwrite 相关操作man fwrite
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
----------------------------------------------------------------------------------------------------
const void *ptr:是读写的数据存放的内存的指针(可以是数组,也可以是新开辟的空间,buffer就是一个索引)
size_t size:一次写入的字节数
size_t nmemb:写入的次数
FILE *stream:目标文件标识符
----------------------------------------------------------------------------------------------------
若成功写入文件,函数返回值为写入次数(函数第三个参数),若失败,返回非写入字节个数或0。
10.3基本格式-fread
查看fread相关操作man fread
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
--------------------------------------------------------------------------------------------------------
const void *ptr:是读写的数据存放的内存的指针(可以是数组,也可以是新开辟的空间,buffer就是一个索引)
size_t size:一次写入的字节数
size_t nmemb:写入的次数
FILE *stream:目标文件标识符
------------------------------------------------------------------------------------------------------------
若成功读出文件,函数返回值为读取总共字节个数(函数第三个参数),若失败,返回非写入字节个数或0。
10.4基本格式-fseek
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
--------------------------------------------------------------------------------------------------------
FILE *stream: 是要移动光标的文件的指针
long offset:针对whence光标偏移个数
int whence:光标的绝对位置
10.5编程实战
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
char *str = "xiaoqiang jiayou";
char readBuf[128] = {0};
fp = fopen("./qiang.txt","w+");
//fwrite(ptr,sizeof(char)*strlen(str),1,fp);
//以下两种方法都可以
fwrite(str,sizeof(char),strlen(str),fp);//每次写一个字节sizeof(char),写strlen(str)次
//fwrite(str,sizeof(char)*strlen(str),1,fp)//每次写sizeof(char)*strlen(str)字节,写1次
//int fseek(FILE *stream, long offset, int whence);
fseek(fp,0,SEEK_SET);
//fread(readBuf,sizeof(char)*strlen(str),1,fp));
//以下两种方法都可以
fread(readBuf,sizeof(char),strlen(str),fp);//每次读一个字节sizeof(char),读strlen(str)次
//fread(redBuf,sizeof(char)*strlen(str),1,fp);//每次读sizeof(char)*strlen(str)字节,读1次
printf("read data: %s\n",readBuf);
fclose(fp);
return 0;
}
11.标准C库写入结构体到文件
11.1编程实战
#include <stdio.h>
#include <string.h>
struct Test
{
int idata;
char cdata;
};
int main()
{
FILE *fp;
struct Test t1 = {100,'a'};
struct Test t2;
fp = fopen("./file1","w+");
//fwrite(ptr,sizeof(char)*strlen(str),1,fp);
int n_write = fwrite(&t1,sizeof(struct Test),1,fp);
//int fseek(FILE *stream, long offset, int whence);
fseek(fp, 0, SEEK_SET);
//fread(readBuf,sizeof(char)*strlen(str),1,fp));
int n_read = fread(&t2,sizeof(struct Test),1,fp);
printf("read %d %c\n",t2.idata,t2.cdata);
//int fclose(FILE *stream);
fclose(fp);
return 0;
}
12.文件其他函数讲解及文件的收尾
12.1基本格式–fputc、fgetc
查看fputc的相关操作man fputc
#include<stdio.h>
int fputc(int c, FILE *stream);//写入字符
int fgetc(FILE *stream);//读出字符
-----------------------------------------------------------------------------------
fputc:若成功写入文件,函数返回值为写入文件的字符的ASCII码值,若出错,返回EOF(-1)。
fgetc:若成功读出文件,函数返回值为读出文件的内容,若出错或读到末尾,返回EOF(-1)。
12.2编程实战
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
int i;
char *str = "xiaoqiang jiayou";
int len = strlen(str);
fp = fopen("./test.txt","w+");
for(i=0;i<len;i++){
fputc(*str,fp);
str++;
}
fclose(fp);
return 0;
}
12.3基本格式–feof
#include <stdio.h>
int feof(FILE *stream);
-------------------------------------------------------------------------------------------------
FILE *stream:是要判断的文件的指针
-------------------------------------------------------------------------------------------------
若到文件末尾,函数返回值为非0,若不到末尾,返回0。
12.4编程实战
#include <stdio.h>
#include <string.h>
int main()
{
FILE *fp;
char c;
fp = fopen("./test.txt","r");
while(!feof(fp)){//若到文件末尾,函数返回值为非0,若不到末尾,返回0。
c = fgetc(fp);
printf("%c",c);
}
fclose(fp);
return 0;
}