一、linux几个目录
1. /bin 用于储存普通用户可执行的命令,如ls,cp
2. /boot linux内核及启动系统是所需要的文件,保证启动文件安全
3. /dev 设备文件的储存目录,如硬盘,光驱(更体现一切皆文件)
4. /etc 用于存放系统的配置文件,比如账户密码
5. /home 普通用户主目录
6. /lib 用于存放各种库文件
7. /proc 该目录是一个虚拟文件系统,只有在系统运行时才存在。可以获取系统的状态信息并且修改某些系统的配置信息。cat/proc/memifo可以获取系统内存的使用状态
8. /sbin是用来存放用于管理系统的命令
9. /tmp 临时文件目录
10. /usr 用于存放系统应用程序及相关文件,如说明文档,帮助文档
11. /var用于存放系统中经常变化的文件,如日志文件,用户邮件
二、文件系统模型
物理磁盘的访问都是通过设备驱动程序进行的。对设备驱动的访问有两种途径:1、通过设备驱动本身提供的接口 2、通过虚拟文件系统提供给上层应用程序的接口(与proc相同,都是只存在与内存而不存在与磁盘之中)
三、文件访问权限
1.r=4,w=2,x=1
2.int chmod(const char *path,mode_t mode)
和int fchmod(intflides,mode_t mode)
头文件是#include<sys/types.h>
和#include<sys/sta.h>
3.mode的参数
参数 | 八进制 | 含义 |
---|---|---|
S_IRUSR(S_IREAD) | 0400 | 文件所有者具可读 |
S_IWUSR(S_IWRITE) | 0200 | 文件所有者具可写入权限 |
S_IXUSR(S_IEXEC) | 00100 | 文件所有者具可执行权限 |
S_IRGRP | 00040 | 用户组具可读取权限 |
S_IWGRP | 00020 | 用户组具可写入权限 |
S_IXGRP | 00010 | 用户组具可执行权限 |
S_IROTH | 00004 | 其他用户具可读取权限 |
S_IWOTH | 00002 | 其他用户具可写入权限 |
S_IXOTH | 00001 | 其他用户具可执行权限 |
my_chmod.c
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
int main(int argc,char **argv)
{
int mode;
int mode_u;
int mode_g;
int mode_o;
char *path;
if(argc<3)//保证和命令chmod的参数相同
{
printf("%s <mode num> <target file>\n",argv[0]);
exit(0);
}
mode=atoi(argv[1]);//这里默认你现在获得的参数就是8进制
if(mode>777||mode<0)//保证输入在范围之内
{
printf("mode num error\n");
exit(0);
}
mode_u=mode/100;//求出各个位数
mode_g=(mode-(mode_u*100))/10;
mode_o=mode-(mode_u*100)-(mode_g*10);
mode=(mode_u*8*8)+mode_g*8+mode_o;//这里是8进制转换为十进制
path=argv[2];//实际就是将字符串首地址给了path
if(chmod(path,mode)==-1)//chmod会认为你输入就是10进制,内部会处理,所以这个chmod程序只能说是一个简化
{
perror("chmod errorr");//输出错误信息
//perror(s) 用来将上一个函数发生错误的原因输出到标准设备(stderr)
exit(1);
}
return 0;
}
四、文件打开和关闭
1、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);
//具体用哪一个,是由参数flags决定
2.creat函数
int creat(const char *pathname,mode_t mode);
creat只能以只写的方式打开创建的文件
3.close函数
int clode(int fd)
- 成功调用返回一个文件描述符号,否则返回-1
my_creat.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int fd;
if((fd=open("example_62.c",O_CREAT|O_EXCL,S_IRUSR|S_IWUSR))==-1)
// if((fd=creat("example_62.c",S_IRWXU))==-1)
{
perror("open");
// printf("open:%s with errno:%d\n",strerror(errno),errno);/;/strerror会把错误以字符串形式输出,errno是全局变量对应数字是错误
exit(1);
}
else
{
printf("create file success!\n");
}
close(fd);
return 0;
}
mode参数 | 含义 |
---|---|
O_RDONLY | 只读打开 |
O_WRONLY | 只写打开 |
O_RDWR | 读写打开 |
O_SEARCH | (仅对目录有意义)只搜索打开 |
O_APPEND | 每次写文件时都追加到文件的尾部 |
O_CLOEXEC | 将FD_CLOEXEC设置为文件描述符标志 |
O_CREAT | 若该文件不存在则创建 |
O_EXCL | (指定了O_CREAT)若文件已存在则报错 |
O_NOFOLLOW | 若文件是一个符号链接则报错 |
O_SYNC | 对文件的修改将阻塞直到物理磁盘上同步为止 |
O_DIRECTORY | 若文件不是一个目录则失败 |
O_NONBLOCK | 以非阻塞的方式打开文件 |
O_NDELAY | 以非阻塞方式打开文件 |
O_TRUNC | 当文件存在并以可写方式打开则截断文件至0 |
errno定义的那些内容可以通过程序输出(这里感谢殷大佬的提示)
#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<string.h>
#include<errno.h>
int main(void)
{
int i;
for(i = 0;i < 140;i++)
{
errno = i;
printf("%d error:%s\n",errno,strerror(errno));
}
return 0;
}
五、文件的读写
1、read函数
#include<unistd.h>
ssize_t read(int fd,void *buf,size_t count);
//从文件描述符fd所指向的文件中读取count个字节到buf中
//返回值表示世界读取字节数
2、write是从buf中读取count个字节到fd中
返回值相同
3、lseek函数
#include<unistd.h> #include<sys/types.h>
//和fseek类似
注意:
①fseek()不像lseek()会返回读写位置, 因此必须使用ftell()来取得目前读写的位置.
②lseek当调用成功时则返回目前的读写位置, 也就是距离文件开头多少个字节. 若有错误则返回-1, errno 会存放错误代码.
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<stdlib.h>
void my_err(const char *err_string,int line)//错误处理
{
fprintf(stderr,"line:%d ",line);
perror(err_string);
exit(1);
}
int my_read(int fd)//读数据
{
int len;
int ret;
int i;
char read_buf[64];
//SEEK_END表示结束
//SEEK_SET表示开头
//SEEK_CUR表示当前位置
if(lseek(fd,0,SEEK_END)==-1)
my_err("lseek",__LINE__);
if((len=lseek(fd,0,SEEK_CUR))==-1)
my_err("lseek",__LINE__);
if((lseek(fd,0,SEEK_SET))==-1)
my_err("lseek",__LINE__);
if((ret=read(fd,read_buf,len))<0)
my_err("read",__LINE__);
printf("len:%d\n",len);
for(i=0;i<len;i++)
{
printf("%c",read_buf[i]);
}
putchar('\n');
return ret;
}
int main()
{
int fd;
char write_buf[32]="hello,world!";
//if((fd=creat("example_63.c",S_IRWXU))==-1)
if((fd=open("example_63.c",O_RDWR|O_CREAT|O_TRUNC,S_IRWXU))==-1)
{
my_err("open",__LINE__);
}
else
printf("create file success\n");
//写数据 if(write(fd,write_buf,strlen(write_buf))!=strlen(write_buf))
my_err("write",__LINE__);
my_read(fd);
printf("/*-----------------*/\n");
if(lseek(fd,10,SEEK_END)==-1)
my_err("lseek",__LINE__);
if(write(fd,write_buf,strlen(write_buf))!=strlen(write_buf))
my_err("write",__LINE__);
my_read(fd);
close(fd);
return 0;
}
六、fcntl系统调用
1、#include<unistd.h>
#include<fcntl.h>
①int fcntl(int fd,int cmd)
②int fcntl(int fd,int cmd,long arg)
③int fcntl(int fd,int cmd,struct flock *lock)
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdlib.h>
void my_err(const char *err_string,int line)//错误处理函数
{
fprintf(stderr,"line:%d ",line);
perror(err_string);
exit(1);
}
int main()
{
int ret;
int access_mode;
int fd; if((fd=open("example_64",O_CREAT|O_TRUNC|O_RDWR,S_IRWXU))==-1)
my_err("open",__LINE__);
if((ret=fcntl(fd,F_SETFL,O_APPEND))<0)//设置文件打开方式
my_err("fcntl",__LINE__);
if((ret=fcntl(fd,F_GETFL,0))<0)//获取文件打开方式
my_err("fcntl",__LINE__);
access_mode=ret & O_ACCMODE;//O_ACCMODE为3,&可以获得ret后两位
if(access_mode==O_RDONLY)
printf("example_64 access_mode:read only");
else if(access_mode==O_WRONLY)
printf("example_64 access_mode:write only");
else if(access_mode==O_RDWR)
printf("example_64 access_mode:write+read");
if(ret&O_APPEND)
printf(" ,append");
printf("\n%d\n",O_APPEND);
printf("\n%d\n",O_NONBLOCK);
printf("\n%d\n",O_SYNC);
if(ret&O_NONBLOCK)
printf(",nonblock");
if(ret&O_SYNC)
printf(" ,sync");
putchar('\n');
return 0;
}
2、锁
共享锁言简意赅就是说大家可以读这个文件
互斥锁就是只能一个人去写这个文件,防止不同人打开,最后文件混乱
int fcntl(int fd,int cmd,struct flock *lock)
struct flock {
short l_type;/*锁的类型F_RDLCK, F_WRLCK, or F_UNLCK*/
off_t l_start;/*相对于l_whence的偏移值,字节为单位*/
short l_whence;/*从哪里开始:SEEK_SET, SEEK_CUR, or SEEK_END*/
off_t l_len;/*长度, 字节为单位; 0 意味着缩到文件结尾*/
pid_t l_pid;/*returned with F_GETLK*/
};
注意:
①cmd为中有一个F_GETTLK只是修改了结构体中锁的类型为F_UNLCK
②程序只是一个进程的时候可以设置写锁之后,设置读锁,但是多个进程的锁是不兼容的,所以下面的例子是单个进程
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<stdlib.h>
void my_err(const char *err_string,int line)
{
fprintf(stderr,"line:%d ",line);
perror(err_string);
exit(1);
}
//锁的设置或释放
int lock_set(int fd,struct flock *lock)
{
if(fcntl(fd,F_SETLK,lock)==0)
{
if(lock->l_type==F_RDLCK)
printf("set read lock,pid:%d\n",getpid());
//getpid()取得进程识别码
else if(lock->l_type==F_WRLCK)
printf("set write lock,pid:%d\n",getpid());
else if(lock->l_type==F_UNLCK)
printf("release lock,pid:%d\n",getpid());
}
else
{
perror("lock operation fail\n");
return -1;
}
}
//测试锁
int lock_test(int fd,struct flock *lock)
{
if(fcntl(fd,F_GETLK,lock)==0)
{
if(lock->l_type==F_UNLCK)
{
printf("lock can be set in fd\n");
return 0;
}
else
{
if(lock->l_type==F_RDLCK)
printf("can't set lock,read lock has been set by:%d\n",lock->l_pid);
else if(lock->l_type==F_WRLCK)
printf("can't set lock,write lock has been set by:%d\n",lock->l_pid);
}
return -2;
}
else
{
perror("get incompatible locks fail");
return -1;
}
}
int main()
{
int fd;
int ret;
struct flock lock;
char read_buf[32];
//打开文件
if((fd=open("example_65",O_CREAT|O_TRUNC|O_RDWR,S_IRWXU))==-1)
my_err("open",__LINE__);
if(write(fd,"test lock",10)!=10)
my_err("write",__LINE__);
//初始化
memset(&lock,0,sizeof(struct flock));
lock.l_start=SEEK_SET;
lock.l_whence=0;
lock.l_len=0;
//设置读锁
lock.l_type=F_RDLCK;//就是检测可不可以设置读锁
if(lock_test(fd,&lock)==0)
{
lock.l_type=F_RDLCK;
lock_set(fd,&lock);
}
//读数据
lseek(fd,0,SEEK_SET);
if((ret=read(fd,read_buf,10))<0)
my_err("read",__LINE__);
read_buf[ret]='\0';
printf("%s\n",read_buf);
//任意键
getchar();
//设置写锁
lock.l_type=F_WRLCK;
if(lock_test(fd,&lock)==0)
{
lock.l_type=F_WRLCK;
lock_set(fd,&lock);
}
//释放锁
lock.l_type=F_UNLCK;
lock_set(fd,&lock);
close(fd);
return 0;
}
七、文件属性操作
1、获取文件属性int lstat(int fileds,char *file_name,struct stat*buf)
执行成功为0.失败为-1
struct stat {
dev_t st_dev; /*文件所在设备的ID*/
ino_t st_ino; /* 节点号*/
mode_t st_mode; /* 文件的类型和存取的权限*/
nlink_t st_nlink; /* 链向此文件的连接数(硬连接)*/
uid_t st_uid; /* user's id*/
gid_t st_gid; /* group's id*/
dev_t st_rdev; /* 设备号,针对设备文件*/
off_t st_size; /* 文件大小,字节为单位*/
blksize_t st_blksize; /* 系统块的大小*/
blkcnt_t st_blocks; /* 文件所占块数*/
time_t st_atime; /* 最近存取时间*/
time_t st_mtime; /* 最近修改时间*/
time_t st_ctime; /*最后状态修改时间*/
};
宏定义好的几个函数
参数 | 含义 |
---|---|
S_ISLNK(st_mode) | 是否是一个连接 |
S_ISREG(st_mode) | 是否是一个常规文件 |
S_ISDIR(st_mode) | 是否是一个目录 |
S_ISCHR(st_mode) | 是否是一个字符设备 |
S_ISBLK(st_mode) | 是否是一个块设备 |
S_ISFIFO(st_mode) | 是否 是一个FIFO文件 |
S_ISSOCK(st_mode) | 是否是一个SOCKET文件 |
2、设置文件属性
mode_t unmask(mode_t mask)屏蔽属性
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
int main()
{
umask(0);//不屏蔽
if(creat("example_681.test",S_IRWXU|S_IRWXG|S_IRWXO)<0)
{
perror("creat");
exit(1);
}
umask(S_IRWXO);//其他用户没有可读可写可执行
if(creat("example_682.test",S_IRWXU|S_IRWXG|S_IRWXO)<0)
{
perror("creat");
exit(1);
}
return 0;
}
八、目录的创建和删除、切换
1、目录的创建
#include<sys/stat.h>
#include<sys/typed.h>
int mkdir(const char *pathname,mode_t mode);
2、目录删除
#include<unistd.h>
int mkdir(const char *pathanme)
- 注意:只能删除空目录
3、获取当前目录
#include<unistd.h>
char *getcwd(char *buf,size_t size);
char *get_current_dir_name(void)
char *getwd(char *buf)
①get_current_dir_name获取当前工作目录
#define _GNU_SOURCE
/*这是用来让用户配置编译环境的头文件。再看一下_GUN_SOURCE这个宏,这个宏可以让用户打开所有features.h文件的属性,而且其他头文件在获得这个宏定义之后才可以使用get——current_dir_name这个函数*/
#include<stdio.h>
#include <stdio.h>
#include <unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
char *path;
path = get_current_dir_name();
printf("%s>\n",path);
exit(0);
}
/*用gcc -E将预处理的代码导出来查看,如果宏定义的位置不正确。
导出的代码中不会包含get_current_dir_name()的函数原型,自然编译就认为它的返回值是默认的整数,从而导致一个警告。
把宏定义放在前面之后,gcc -E导出的代码中已经包含了正确的函数原型,警告就不会出现了。*/
②getcwd函数获取绝对路径
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(void)
{
char *path = NULL;
path = getcwd(NULL,0);
/*或者使用方法getcwd(path,256),256是给path分配的空间,path就储存了空间*/
puts(path);
free(path);
return 0;
}
/*可以采取令 buf 为 NULL并使 size 为零,来使 getcwd 调用 malloc 动态给 buf 分配,但是这种情况要特别注意使用后释放缓冲以防止内存泄漏。*/
4、切换工作目录
#include<unistd.h>
int chdir(const char *path);//path是目录参数
int fchdir(int fd);//fd是文件描述符号
例子是fchdir的使用
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main()
{
int fd;
fd = open("../", O_RDONLY);
fchdir(fd);
printf("current working directory : %s \n", getcwd(NULL, 0));
close(fd);
}
九、获取目录信息
1、opendir
#include<sys/types.h>
#include<dirent.h>
DIR *opendir(const char *name)
失败返回NULL
2.readdir
#include<sys/types.h>
#include<dirent.h>
原型DIR *readdir(DIR*dir)
struct dirent{
long d_ino;//索引节点号
off_t d_off;//在文件中偏移量
unsigned short d_reclen;//文件名长
char d_name[NAME_MAX+1];
}
3.closedir
#include<sys/types.h>
#include<dirent.h>
原型DIR *closedir(DIR*dir)
#include<stdio.h>
#include<dirent.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int my_readir(const char *path)
{
DIR *dir;
struct dirent *ptr;
if((dir=opendir(path))==NULL)
{
perror("opendir");
return -1;
}
while((ptr=readdir(dir))!=NULL)//直到NULL才会停止读取
printf("File name:%s\n",ptr->d_name);
closedir(dir);
return 0;
}
int main(int argc,char *argv[])
{
if(argc<2)//判断参数
{
printf("listfile <target path>\n");
exit(1);
}
if(my_readir(argv[1])<0)
exit(1);
return 0;
}
注意:
这里所说的打开目录,只是获取了目录的信息,没有实际的进入你所打开的目录,你可以获取进入目录的名字,如果想切换目录,必须用chdir或fdir。用opendir打开,如果再想更深层次进入打开目录的目录是不可以的,opendir没有将你的目录切换。
比如你在linux目录下有一个ls目录,你打开了ls,发现ls目录下有个fun目录,你想进fun看看有什么,你会再次用opendir打开fun这个目录,但是实际上opendir会在linux目录下找fun,因为你的工作目录没有切换,当然linux下没有fun这个目录,就会报错。