文章目录
linux下文件夹操作
系统提供了一下库函数来操作文件夹:
相关API函数
opendir(3)
DIR *opendir(const char *name);
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开一个文件夹
参数:
name:指定了要打开的文件夹的名字
返回值:
NULL 错误 errno被设置
返回一个具体的地址
closedir(3)
int closedir(DIR *dirp);
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭一个文件夹
参数:
dirp:指定了要关闭的文件夹(opendir(3)的返回值)
返回值:
0 成功
-1 失败 errno被设置
readdir(3)
struct dirent *readdir(DIR *dirp);
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取文件夹的内容
参数:
dirp:指定文件夹。opendir(3)的返回值
返回值:
NULL 到达文件夹的末尾或者错误产生
如果errno被设置了,代表了错误产生
成功调用返回一个地址。
struct dirent{
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all file system types */
char d_name[256]; /* filename */
};
代码示例:
- diros.c
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
int main(int argc,char *argv[]){
struct dirent *p;
//打开指定的文件夹
DIR *dirp=opendir(argv[1]);
if(dirp==NULL){
perror("opendir");
return 1;
}
printf("directory open success..\n");
while((p=readdir(dirp))!=NULL){
printf("%s\t%lu\n",\
p->d_name,p->d_ino);
}
//关闭文件夹
closedir(dirp);
return 0;
}
- 执行结果
文件重定向就是重新定位文件的流向。要完成文件重定向的功能,需要将文件描述符进行拷贝。
相关API函数
dup(2)
int dup(int oldfd);
#include <unistd.h>
int dup(int oldfd);
功能:复制一个文件描述符
参数:
oldfd:拷贝的样本
返回值:
-1 失败 errno被设置
新的文件描述符
dup2(2)
int dup2(int oldfd, int newfd);
功能:复制一个文件描述符
参数:
oldfd:拷贝的样本
newfd:指定新的文件描述符
返回值:
-1 失败 errno被设置
新的文件描述符
代码示例
- direct.c
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void){
int fd,s_fd;
char msg[]="this is a test\n";
fd=open("somefile",O_RDWR|O_CREAT,\
0664);
if(fd==-1){
perror("open");
return 1;
}
//复制标准输出文件描述符到s_fd
s_fd=dup(STDOUT_FILENO);
//将fd文件描述符复制到标准输出
dup2(fd,STDOUT_FILENO);
close(fd);
//向标准输出文件描述符中输出字符串
write(STDOUT_FILENO,msg,strlen(msg));
dup2(s_fd,STDOUT_FILENO);
write(STDOUT_FILENO,msg,strlen(msg));
close(s_fd);
return 0;
}
- 执行结果
文件锁分为两种类型:
- 强制锁
- 建议锁
根据锁的互斥性又可以分为读锁(共享锁)、写锁(互斥锁)。
相关使用方式
使用fcntl完成文件锁的功能:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );
功能:操作文件描述符
参数:
fd:指定要操作的文件描述符
cmd:对文件描述符的操作命令
F_GETLK 获取文件上的锁
F_SETLK 设置锁到文件。出现互斥锁的时候,非阻塞。
F_SETLKW 设置锁到文件,出现互斥锁的时候,阻塞。
返回值:
0 成功
-1 错误 errno被设置
struct flock {
short l_type; /* Type of lock: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* How to interpret l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* Starting offset for lock */
off_t l_len; /* Number of bytes to lock */
pid_t l_pid; /* PID of process blocking our lock
(F_GETLK only) */
};
代码示例
两个进程同时给一个文件添加读锁。
- processA.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(void){
int fd;
//以读写方式打开文件
fd=open("hello",O_RDWR);
if(fd==-1){
perror("open");
return 1;
}
//定义锁变量
struct flock lock;
//初始化锁变量的字段内容
lock.l_type=F_RDLCK;
lock.l_whence=SEEK_SET;
lock.l_start=0;
lock.l_len=6;
//给hello文件加读锁
int f=fcntl(fd,F_SETLK,&lock);
if(f==-1){
perror("fcntl");
return 2;
}
printf("添加读锁成功...\n");
getchar();
close(fd);
return 0;
}
- processB.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(void){
int fd;
//以读写方式打开文件
fd=open("hello",O_RDWR);
if(fd==-1){
perror("open");
return 1;
}
//定义锁变量
struct flock lock;
//初始化锁变量的字段内容
lock.l_type=F_WRLCK;
lock.l_whence=SEEK_SET;
lock.l_start=0;
lock.l_len=6;
//给hello文件加读锁
int f=fcntl(fd,F_SETLKW,&lock);
if(f==-1){
perror("fcntl");
return 2;
}
printf("B添加读锁成功...\n");
getchar();
close(fd);
return 0;
}
- 执行结果:
读锁结果
修改B进程为写锁尝试:
发现B进程会在A进程使用期间阻塞等待。
库函数:(缓冲文件)fopen、fclose、fputc、fgetc。
系统调用:(非缓冲文件)open、close、write、read。
具体说明
fopen(3)
分配结构体FILE的一块内存,在FILE类型中有一个成员变量_fileno,用于保存文件描述符。另外分配一块缓存,后边库函数对文件的读写操作是针对这块缓存的;调用open(2)打开相应的文件。
fgetc(3)
调用fgetc的时候,主要是针对缓存,从缓存中获取数据,如果缓存有数据,立即返回获取到的数据。如果缓存中没有数据,调用read(2),文件描述符有FILE类型的参数的_fileno传入。从系统中获取数据到缓存,然后fgetc(3)返回获取到的数据。
fputc(3)
调用fputc的时候,如果写缓存有空间,直接将字符写入到缓存;如果写缓存已经满,调用write(2)将写缓存中的内容写到文件,清楚缓存,然后将字符写入到写缓存。
fclose(3)
先清除缓存中的内容到文件,然后调用close(2)关闭文件描述符,然后,释放fopen(3)开辟的缓存空间。
代码示例
- file.c
#include <stdio.h>
int main(void){
FILE *fp;
fp=fopen("hello","r");
if(fp==NULL){
perror("fopen");
return 1;
}
printf("file open success...\n");
fclose(fp);
return 0;
}
- 执行结果
程序和进程的区别:
- 程序是静态的,存放在磁盘上,是指令的集合。
- 进程是程序运行的实例,一个程序运行一次会产生一个进程。
每个进程都有自己的pid,每个进程都有自己的PCB。进程是资源分配的基本单位。
在linux操作系统下,进程直接的关系是斧子关系或者兄弟关系。
所有的用户级进程形成了一颗树,使用pstree可以查看这个树,init是这棵树的树根,也就是1号进程(用户进程的第一个进程)。
相关API
如果创建一个新的进程?
使用系统调用fork(2)创建新进程。
pid_t fork(void);
#include <unistd.h>
pid_t fork(void);
功能:创建一个子进程
参数:
void
返回值:
-1错误,在父进程里返回,子进程不被创建。errno被设置。
成功:
在父进程里返回子进程的pid。
在子进程中0被返回。
代码示例
- fork.c
#include <stdio.h>
#include <unistd.h>
int main(void){
pid_t pid;
//创建子进程
pid=fork();
if(pid ==-1){
perror("fork");
return 1;
}
if(pid==0){//子进程执行的代码
printf("child\n");
}else{//福进程执行的代码
printf("parent\n");
}
return 0;
}
- 执行结果