linux下文件、文件夹相关操作(C语言)


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;
}

  • 执行结果
    在这里插入图片描述

linux进程基础

程序和进程的区别:

  • 程序是静态的,存放在磁盘上,是指令的集合。
  • 进程是程序运行的实例,一个程序运行一次会产生一个进程。

每个进程都有自己的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;
}

  • 执行结果
    在这里插入图片描述
发布了102 篇原创文章 · 获赞 27 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_37596943/article/details/104178210