Unix_Linux环境c语言(一)
本周主要对环境介绍,文件操作与文件管理进行了学习。
一、静态库、共享库、动态加载共享库的创建和应用
静态库
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);
}
}
上一篇: Linux内核中设备树DTS
下一篇: Magento秒杀活动那么些破事