欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unix_Linux环境c语言(一)

程序员文章站 2024-01-23 18:26:10
...

本周主要对环境介绍,文件操作与文件管理进行了学习。

一、静态库、共享库、动态加载共享库的创建和应用

静态库

1、创建静态库
		编写源代码:vi .c/.h
		编译源代码:gcc -c xxx.c -> xxx.o
		打包生成静态库:ar -r libxxx.a x1.o x2.o ...
		ar命令的一些参数:
			-r 把目标文件添加到静态库中,已经存在的更新
			-q 将目标文件追加到静态库的末尾
			-d 从静态库中删除目标文件
			-t 显示静态库中有哪些目标文件
			-x 把静态库拆分成目标文件
	2、调用静态库
		直接调用:调用者要和库在同一路径下
			gcc main.c libxxx.a
		设置环境变量:设置方法与C_INCLUDE_PATH类似
			1.打开 vim ~/.bashrc 文件
			2.在文件末尾添加一行
				export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径
			3.重新加载配置文件 source ~/.bashrc
			4.编译时要指定库名
				gcc main.c -lmath
		设置编译参数:-L路径
			gcc main.c -L路径 -lmath	
	3、运行
		在编译时已经把被函数的二进制复制到可执行文件中了,在执行时不再需要静态库文件。

共享库

1、创建共享库
		编写源代码:vi .c/.h
		编译出位置无关目标文件:
			gcc -c -fpic xxx.c -> xxx.o
		链接生成共享库:
			gcc -shared x1.o x2.o x3.0 ... -o libxxx.so
	2、调用共享库
		直接调用:调用者要和库在同一路径下
			gcc main.c libxxx.so
		设置环境变量:设置方法与C_INCLUDE_PATH类似
			1.打开 vim ~/.bashrc 文件
			2.在文件末尾添加一行
				export LIBRARY_PATH=$LIBRARY_PATH:库文件的路径
			3.重新加载配置文件 source ~/.bashrc
			4.编译时要指定库名
				gcc main.c -lmath
		设置编译参数:-L路径
			gcc main.c -L路径 -lmath	
	3、运行
		在使用共享库时,调用者只是记录了被代码在库的位置,因此在执行时需要共享库同时被加载。
		操作系统会根据LD_LIBRARY_PATH环境变量的设置来加载共享库。

动态加载共享

#include <dlfcn.h>
	1、加载共享库
	void *dlopen(const char *filename, int flag);
	filename:共享库的库名,或路径
	flag:
		RTLD_LAZY 使用时才加载
		RTLD_NOW 立即加载
	返回值:共享库的句柄(类似文件指针)
	
	2、获取标识符地址并使用
	void *dlsym(void *handle, const char *symbol);
	handle:共享库的句柄
	symbol:标识符的名字
	返回值:标识符在共享库中的位置(地址,可以解引用,或跳转过去)。
	3、卸载共享库
	int dlclose(void *handle);
	handle:共享库的句柄
	返回值:成功返回0,失败返回-1
	
	4、获取错误信息
	char *dlerror(void);
	返回值:会把在使用共享库的过程中出现的错误,以字符串形式返回

二、环境变量的获取与修改

1、环境变量表
	每个程序运行时操作系统都会把所有的环境变量记录到一张表中,传给程序。
	通过main函数参数
		获取int main(int argc, char* argv[],char* environ[])
	通过声明全局变量来获取
		extern char** environ;
2、环境变量函数
	char * getenv(const char *name);
	功能:根据环境变量名,获取环境变量的值
	int putenv (char *string):
	功能:以name=value形式设置环境变量,如果name存在则更新,不存在就加载。
	返回值:成功返回0,失败返回-1
	int setenv (const char *name,const char *value,int overwrite);
	功能:设置name环境变量的值为value,如果name存在且overwrite不为零则更新,否则不变。
	int unsetenv(const char *name);
	功能:从环境变量表中删除name
	int clearenv(void);
	功能:清空环境变量表。
	操作系统记录的环境变量的数据记录一块特殊的存储空间,而在程序自己添加的环境变量需要自己准备存储空间。
	注意:对于环境变量的修改,只能影响自己,不能影响别人。

三、系统调用IO

系统IO与标准IO的区别:

因为标准IO使用了缓冲技术,当数据写入时并没有立即把数据交给内核,而是先放在缓冲区中,当缓冲区满时,会一次性把缓冲区中的数据交给内核写入到文件中,这样就减少内核态与用户态的切换次数。
而系统IO每写一次数据就要进入一次内核态,这样就浪费了大量时间进行内核态与用户态的切换,因此用时更长。
如果为系统IO设置更大的缓冲区,它会比标准IO更快

int open(const char *pathname, int flags);
功能:打开文件

int open(const char *pathname, int flags, mode_t mode);
功能:创建文件

int close(int fd);
功能:删除文件

ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取数据到内存

ssize_t write(int fd, const void *buf, size_t count);
功能:把数据写入到文件

off_t lseek(int fd, off_t offset, int whence);
功能:设置当前文件位置指针

int dup(int oldfd);
功能:复制文件描述符,操作系统会从未使用的文件描述符中选择一个返回。

int dup2(int oldfd, int newfd);
功能:复制指定的文件描述符,如果newfd已经被使用,则先关闭,再复制。

void sync(void);
功能:把所有缓冲区中的数据全部同步到磁盘

int fsync(int fd);
功能:指定fd文件的缓冲区数据同步到磁盘,只针对一个文件,数据同步到磁盘后才返回。

int fdatasync(int fd);
功能:指定fd文件的缓冲区数据同步到磁盘,但仅是文件的数据,并不同步文件属性。

int fcntl(int fd, int cmd, long newfd);
cmd:F_DUPFD
功能:复制文件描述符,与fd操作同一个文件

int fcntl(int fd, int cmd,void/long );
功能:设置或获取文件描述符标志
cmd:F_GETFD void

int fcntl(int fd, int cmd,void/long );
功能:获取文件状态标志(此文件打开的权限以及打开的方式)
cmd:
F_GETFL void
O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC 不能获取到
返回值:带有文件状态标志的int类型变量,需要与各种标志 & 得到
F_SETFL long
O_APPEND, O_ASYNC,O_DIRECT, O_NOATIME,O_NONBLOCK 仅能设置的

int fcntl(int fd, int cmd,struct* flock );
功能:为文件加锁,能锁整个文件或者一部分内容
一旦进程关闭,锁会自动取消。
cmd:
F_GETLK 获取锁的信息
F_SETLK 设置文件锁
F_SETLKW 测试锁
注意:加锁并不能让其他进程打不开文件或不能操作,而是使用者都要遵守锁的约定,确保文件不混乱。

int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
功能:用来获取文件的属性,返回值:成功返回0,失败返回-1

int access(const char *pathname, int mode);
功能:测试当前用户对文件的访问权限,或者文件是否存在。

mode_t umask(mode_t mask);
功能:设置并获取权限屏蔽码,功能与umask命令一样

int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
功能:修改文件的权限,成功返回0,失败返回-1。
注意:它们不受权限屏蔽码的干扰。

int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
功能:修改文件的大小,成功返回0,失败返回-1。

int link(const char *oldpath, const char *newpath);
功能:创建硬链接文件,硬链接指向的是文件的内容,因此当链接目标被删除后,依然可以访问文件的内容。

int unlink(const char *pathname);
功能:删除硬链接文件

int remove(const char *pathname);
功能:删除文件,该函数是标准库中的珊瑚文件函数,底层调用了unlink系统调用。

int rename(const char *oldpath, const char *newpath);
功能:文件重命名

int symlink(const char *oldpath, const char *newpath);
功能:创建一个软链接(目录只能创建软链接)

ssize_t readlink(const char *path, char *buf, size_t bufsiz);
功能:读取软链接文件的内容而非链接目标(open打开软链接文件时,打开的是目标文件)。

int mkdir(const char *pathname, mode_t mode);
功能:创建目录,目录一定要有执行权限,否则无法进入。

int rmdir(const char *pathname);
功能:删除空目录

char *getcwd(char *buf, size_t size);
功能:获取当前进程的工作目录,工作目录是指当不加路径信息时,创建/打开时从那个目录下查找,工作目录默认是程序所在的目录。

int chdir(const char *path);
功能:修改进程的工作目录

int fchdir(int fd);
功能:修改进程的工作目录

DIR *opendir(const char *name);
功能:打开一个目录流

DIR *fdopendir(int fd);
功能:使用文件描述符获取目录流,fd必须是目录文件的

int closedir(DIR *dirp);
功能:关闭目录流

void rewinddir(DIR *dirp);
功能:把目录流的位置指针调整到开头

long telldir(DIR *dirp);
功能:获取当前目录流的位置指针在第几个文件结点

void seekdir(DIR *dirp, long offset);
功能:调整当前目录流的位置指针。

通过上述的学习,实现了一下两个程序
实现ls -l的功能

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h>
#include <dirent.h>
#include <grp.h>
#include <string.h>
#include <time.h>

char* file_mode(mode_t m,char* str)
{
	if(S_ISREG(m))
		str[0] = '-';
	else if(S_ISDIR(m))
		str[0] = 'd';
	else if(S_ISCHR(m))
		str[0] = 'c';
	else if(S_ISBLK(m))
		str[0] = 'b';
	else if(S_ISFIFO(m))
		str[0] = 'q';
	else if(S_ISLNK(m))
		str[0] = 'l';
	else if(S_ISSOCK(m))
		str[0] = 's';
	else 
		str[0] = '?';

	str[1] = '\0';

	strcat(str,S_IRUSR&m?"r":"-");
	strcat(str,S_IWUSR&m?"w":"-");
	strcat(str,S_IXUSR&m?"x":"-");

	strcat(str,S_IRGRP&m?"r":"-");
	strcat(str,S_IWGRP&m?"w":"-");
	strcat(str,S_IXGRP&m?"x":"-");
	
	strcat(str,S_IROTH&m?"r":"-");
	strcat(str,S_IWOTH&m?"w":"-");
	strcat(str,S_IXOTH&m?"x":"-");

	return str;
}

int file_number(mode_t m,char* str)
{
	int num=2;
	if(S_ISDIR(m))
	{
	 	DIR *dp = opendir(str);
		chdir(str);
		if (NULL == dp)
		{
			return num;
		}
		for(struct dirent* de = readdir(dp);NULL != de;de =readdir(dp))
		{
			if (strcmp(".",de->d_name)==0) continue;
			if (strcmp("..",de->d_name)==0) continue;
			int fd = open(de->d_name,O_RDONLY);
			struct stat buf;
			fstat(fd,&buf);
			if(S_ISDIR(buf.st_mode))
			{
				num++;
			}
		}
		chdir("..");
		return num;
		
	}
	return 1;
}

char* file_time(time_t t,char* str)
{
	struct tm* it = localtime(&t);
	sprintf(str,"%2d月 %02d %02d:%02d",it->tm_mon+1,it->tm_mday,it->tm_hour,it->tm_min);
	return str;
}

char* file_uid(uid_t uid,char* str)
{
	struct passwd* wd = getpwuid(uid);
	strcpy(str,wd->pw_name);
	return str;
}

char* file_gid(gid_t gid,char* str)
{
	struct group* gr = getgrgid(gid);
	strcpy(str,gr->gr_name);
	return str;
}

int main()
{
	DIR *dp = opendir(".");
	if (NULL == dp)
	{
		perror("opendir");
		return -1;
	}
	for(struct dirent* de = readdir(dp);NULL != de;de =readdir(dp))
	{
		if (strcmp(".",de->d_name)==0) continue;
		if (strcmp("..",de->d_name)==0) continue;
		int fd = open(de->d_name,O_RDONLY);
		char str_mode[255]={},str_time[255]={},str_uid[255]={};
		char str_gid[255]={};
		struct stat buf;
		fstat(fd,&buf);
		printf("\e[0;30m""%s ",file_mode(buf.st_mode,str_mode));//文件权限
		printf("%d ",file_number(buf.st_mode,de->d_name));//文件数量
		printf("%s ",file_uid(buf.st_uid,str_uid));//文件用户id
		printf("%s ",file_gid(buf.st_gid,str_gid));//文件用户gid
		printf("%5lu ",buf.st_size);//文件大小
		printf("%s ",file_time(buf.st_mtime,str_time));//文件时间
		if(S_ISDIR(buf.st_mode))
		{	
			printf("\e[1;34m""%s\n",de->d_name);//目录名称
		}
		else if (strcmp("a.out",de->d_name)==0)
		{
			printf("\e[1;32m""%s\n",de->d_name);//a.out文件名称
		}
		else
		{
			printf("\e[0;30m""%s\n",de->d_name);//文件名称
		}
	}
	printf("\e[0;30m""\n");
}

实现rm -rf的功能(删除非空目录)

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>

void delete_file(char *str)
{
	DIR * dp = opendir(str);
	if (NULL ==dp)
		return ;
	chdir(str);
	for(struct dirent* de = readdir(dp);NULL != de;de =readdir(dp))
	{
		if (strcmp(".",de->d_name)==0) continue;
		if (strcmp("..",de->d_name)==0) continue;
		int fd = open(de->d_name,O_RDONLY);
		struct stat buf;
		fstat(fd,&buf);
		if(S_ISDIR(buf.st_mode))
		{
			delete_file(de->d_name);
			chdir("..");
			rmdir(de->d_name);
		}
		else 
		{
			remove(de->d_name);
		}
	}
}



int main()
{
	char str[255]={};
	printf("请输入要删除的文件");
	gets(str);
	int fd =open(str,O_RDONLY);
	struct stat buf;
	fstat(fd,&buf);
	if(S_ISDIR(buf.st_mode))
	{
		delete_file(str);
		chdir("..");
		rmdir(str);
	}
	else
	{
		remove(str);
	}

}