一、创建模式
使用"ls -l"命令,可以看到下图所示,其中红圈- rwx rwx r-x
分别
“-” :代表普通文件
“rwx” :代表我自己对于该文件的权限为可读、可写、可执行,4 2 1
“rwx” :代表同组对于该文件的权限为可读、可写、可执行,4 2 1
"r-x" :代表其他组对于该文件的权限为可读、可执行,4 1
- 常见创建模式
宏表示 | 数字 |
---|---|
S_IRUSR | 4 可读 |
S_IWUSR | 2 可行 |
S_IXUSR | 1 可执行 |
S_IRWXU | 7 可读可写可执行 |
二、创建文件creat()函数
int creat(const char *filename,mode_t mode)
filename:要打开的文件名(含路径,缺省为当前路径)
mode:创建模式
三、open()函数—文件打开,close()
使用“man 2 open”命令可以看到open()函数有两个原型,并且它返回的是一个文件描述符(每个文件打开后会有一个自己的文件描述符,相当于自己的id,以后要打开那个文件就使用它自己的文件描述符),失败返回-1;
- 参数说明
int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_mode);
pathname | 要打开的文件名(含路径,缺省为当前路径) |
flags | |
---|---|
O_ RDONLY | 只读打开 |
O_WRONLY | 只写打开 |
O_RDWR | 可读可写打开 |
当我们附带权限后,打开的文件就只能按照这种权限来操作。
以上这三个常数中应当只指定一个,下列常数是可选择的:
O_CREAT | 若打开的文件不存在则创建它,使用此选项时,需要同时说明第三个参数mode,用其说明该新文件的存取许可权限,例:open(“file”,O_RDWR "竖线"O_CREAT,0600) |
O_EXCL | 如果同时指定了O_CREAT,而文件已经存在,则出错,fd返回-1,并且不打开文件 |
O_APPEND | 每次写时都加到文件的末尾 |
O_TRUNC | 属性去打开文件时,如果这个文件中本来是有内容的,而且为只读或只写成功打开,则将其长度截短为0(把原先的内容干掉,再写) |
mode | 一定是在flags中使用了O_CREAT标志,mode记录待创建的文件的访问权限 |
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd=open("file",O_RDWR);
if(fd==-1){
printf("open fall!!!\n");
fd=open("file",O_RDWR|O_CREAT,0600);
if(fd>0){
printf("create successful!!\n");
}
}
close(fd);
}
open fall!!!
create successful!!
每次open完文件后一定要close文件!!!!!!!
四、写入write()函数
- 原型及头文件
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
- 参数说明
ssize_t | 返回值返回写入数据的大小 |
fd | 文件标识符 |
buf | 存放写入内容的指针变量 |
count | 要写入的大小 |
- 注:如果先后往fd里写入两次数据,那么读取时第一次读到的是前一次数据,第二次对到的是后一次数据
五、光标移动lseek()函数
- 函数原型
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
- 参数说明
off_t | 成功完成后,lseek()返回得到的偏移位置- 从文件开始以字节为单位。在出现错误时, 返回值-1 |
fd | 文件标识符 |
offset | 此时光标要偏移的偏移量,可以用来判断文件大小 |
whence | 1.SEEK_SET 2.SEEK_CUR 3.SEEK_END |
SEEK_SET | 文件头 |
SEEK_CUR | 光标当前位置 |
SEEK_END | 文件尾 |
- 说明:将文件读写指针相对whence移动offset个字节
- lseek()计算文件大小:
int size=lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);//计算完别玩了把光标放到文件头,这样read才有数据
六、读出read()函数
- 原型及头文件
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- 参数说明
ssize_t | 返回值返回写入数据的大小 |
fd | 文件标识符 |
buf | 存放读出内容的指针变量 |
count | 要读出的大小 |
read最多读文件大小,write可以无限写
七、open(),write(),lseek(),read(),close()操作演示
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *buf="linux ubtuntu file programme!";
int fd=open("file",O_RDWR|O_CREAT,0600);
if(fd==-1){
printf("open fall!\n");
exit(0);
}
int a=strlen(buf);
printf("buf=%d\n",a);
int n_write=write(fd,buf,strlen(buf));
int filesize=lseek(fd,0,SEEK_SET);
printf("filesize=%d\n",filesize);
char *readbuf=(char *)malloc(n_write);
memset(readbuf,'\0',n_write);
int n_read=read(fd,readbuf,n_write);
printf("n_read=%d\n",n_read);
close(fd); //每次open()完文件后一定要close();
}
八、文件操作原理简述
-
我们对文件进行操作时,一定要先打开文件,打开成功之后才操作,如果打开失败,就不用进行后边的操作了,最后读写完成后,一定要关闭文件,否则会造成文件损坏。
-
文件平时是存放在块设备中的文件系统文件中的,我们把这种文件叫静态文件,当我们去open打开一个文件时,linux内核做的操作包括:内核在进程中建立一个打开文件的数据结构,记录下我们打开的这个文件;内核在内存中申请一段内存,并且将静态文件的内容从块设备中读取到内核中特定地址管理存放(动态文件)。
-
打开文件以后,以后对这个文件的读写操作,都是针对内存中的这一份动态文件,而不是针对静态文件的,当然我们对动态文件进行读写以后,此时内存中动态文件和块设备文件中的静态文件就不同步了,当我们close关闭动态文件时,close内部内核将内存中的动态文件的内容去更新(同步)块设备中的静态文件。
-
为什么这么设计,不直接对块设备直接操作?
块设备本身读写非常不灵活,是按块读写的,而内存是按字节单位操作的,而且可以随机操作,很灵活。
九、文件标志输入输出
- 对于内核而言,所有打开文件都由文件描述符引用。文件描述符是一个非负整数。当打开一个现存文件或者创建一个新文件时,内核向进程返回一个文件描述符。当读写一个文件时,用open和creat返回的文件描述符标识该文件,将其作为参数传递给read和write。
按照惯例,UNIX shell使用文件描述符0与进程的标准输入相结合,文件描述符1与标准输出相结合。STDIN_FILENO、STDOUT_FILEND、STDERR_FILENO这几个宏代替了0,1,2这几个数。
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>
int main()
{
char readbuf[128];
read(0,readbuf,128);
write(1,readbuf,strlen(readbuf));
return 0;
}
十、小练习
- 实现cp命令
#include<unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void panduanargc(int argc)
{
if(argc<2){
printf("cp: missing file operand\n");
printf("Try 'cp --help' for more information.\n");
exit(0);
}
}
int main(int argc,char **argv)
{
char *readbuf=NULL;
panduanargc(argc);
int fd1=open(argv[1],O_RDWR);
if(fd1==-1){
printf("cp: missing destination file operand after '%s'\n",argv[1]);
printf("Try 'cp --help' for more information.\n");
exit(0);
}
int fd2=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);
//以可读可写打开,没有就创建,并且删除其中所有内容,
if(fd2<0){
printf("%s create fall!\n",argv[2]);
}
int size=lseek(fd1,0,SEEK_END);
lseek(fd1,0,SEEK_SET);
readbuf=(char *)malloc(size);
int n_read=read(fd1,readbuf,size);
write(fd2,readbuf,size);
close(fd1);
close(fd2);
return 0;
}
37,1-8 77%
- 修改file文件中的LONG=9
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
int main()
{
char *readbuf=NULL;
int fd = open("./file",O_RDWR);
if(fd==-1){
printf("open fall!!!\n");
exit(0);
}
int size=lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
readbuf=(char *)malloc(size);
memset(readbuf,'\0',size);
int n_read=read(fd,readbuf,size);
char *p=(char *)malloc(size);
p=strstr(readbuf,"LONG=");
for(int i=0;i<5;i++){
p++;
}
*p='9';
lseek(fd,0,SEEK_SET);
write(fd,readbuf,size);
close(fd);
return 0;
}
- 文件写入整形数和结构体
- 写入整形数
ssize_t write(int fd, const void *buf, size_t count);
因为buf是void形,所有只需要传入变量的地址就行:
#include<sys/types.h>
int main()
{
int fd;
int data=100;
int data2=0;
fd=open("./file1",O_RDWR);
int n_write=write(fd,&data,sizeof(int));
lseek(fd,0,SEEK_SET);
int n_read=read(fd,&data2,sizeof(int));
printf("read %d\n",data2);
close(fd);
return 0;
}
值得注意的是,file文件打开以后显示的是乱码,但并不影响我们read其中的内容,计算机会自动识别;
- 写入结构体
#include<sys/types.h>
struct Test
{
int a;
char c;
}
int main()
{
int fd;
struct Test data={100,'a'};
struct Test data2;
fd=open("./file1",O_RDWR);
int n_write=write(fd,&data,sizeof(struct Test));
lseek(fd,0,SEEK_SET);
int n_read=read(fd,&data2,sizeof(struct Test));
printf("read %d,%c\n",data2.a,data2.c);
close(fd);
return 0;
}