q目录的操作
打开目录——opendir
opendir函数用来打开一个目录文件
#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd); //使用文件描述符,要配合open函数使用
- DIR是用来描述一个打开的目录文件的结构体类型
- 成功时返回目录流指针;出错时返回NULL
读取目录——readdir
readdir函数用来读取目录流中的内容
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
- struct dirent是用来描述目录流中一个目录项的结构体类型
- 包含成员char d_name[256] 参考帮助文档
- 成功时返回目录流dirp中下一个目录项;
- 出错或到末尾时时返回NULL
关闭目录——closedir
closedir函数用来关闭一个目录文件
#include <dirent.h>
int closedir(DIR *dirp);
- 成功时返回0;出错时返回EOF
示例代码
打印指定的目录下所有文件名称
int main(int argc, char *argv[]) {
{
DIR *dirp;
struct dirent *dp;
if (argc < 2) {
printf(“Usage : %s <directory>\n”, argv[0]); return -1;
}
if ((dirp = opendir(argv[1])) == NULL) {
perror(“opendir”); return -1;
}
while ((dp = readdir(dirp)) != NULL) {
printf(“%s\n”, dp->d_name);
}
closedir(dirp);
文件权限和属性
修改文件访问权限
chmod/fchmod函数用来修改文件的访问权限
(等同于shell的chmod命令)
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
- 成功时返回0;出错时返回EOF
- path是文件的路径
- 在vmware和windows共享的文件夹下,有些权限不能改变
- root和文件所有者能修改文件的访问权限
示例:
chmod(“test.txt”, 0666);
获取文件属性
stat/lstat/fstat函数用来获取文件属性
#include <sys/stat.h>
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
- struct stat是存放文件属性的结构体类型
- 成功时返回0;出错时返回EOF
- 如果path是符号链接stat获取的是目标文件的属性;而lstat获取的是链接文件的属性
文件属性结构体-stat
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
unsigned long st_blksize; //块大小(文件系统的I/O 缓冲区大小)
unsigned long st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
文件类型 – st_mode
通过系统提供的宏来判断文件类型:
S_IFMT 0170000 文件类型的位遮罩
S_ISREG(st_mode) 0100000 是否常规文件
S_ISDIR(st_mode) 0040000 是否目录
S_ISCHR(st_mode) 0020000 是否字符设备
S_ISBLK(st_mode) 0060000 是否块设备
S_ISFIFO(st_mode) 0010000 是否FIFO(管道)文件
S_ISLNK(st_mode) 0120000 是否链接文件
S_ISSOCK(st_mode) 0140000 是否SOCKET文件
通过系统提供的宏来获取文件访问权限:
S_IRUSR 00400 bit:8 所有者有读权限
S_IWUSR 00200 7 所有者拥有写权限
S_IXUSR 00100 6 所有者拥有执行权限
S_IRGRP 00040 5 群组拥有读权限
S_IWGRP 00020 4 群组拥有写权限
S_IXGRP 00010 3 群组拥有执行权限
S_IROTH 00004 2 其他用户拥有读权限
S_IWOTH 00002 1 其他用户拥有写权限
S_IXOTH 00001 0 其他用户拥有执行权限
练习-获取并显示文件属性
类似于ll和ls -l命令
题目:
以下面格式打印指定文件的主要信息:
$ ./a.out test.c
-rw-r–r-- 317 2014-11-08 test.c
思路:
- 调用lstat函数获取文件的属性
- 从stat结构体中获取相应信息并输出
代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
int main (int argc,char **argv){
struct stat buf;
int ret;
ret = stat("chmod_t.c",&buf);
if(ret<0){
perror("stat");
return 0;
}
if(S_ISREG(buf.st_mode)){
printf("-");
}
if(S_ISDIR(buf.st_mode)){
printf("d");
}
if(S_ISCHR(buf.st_mode)){
printf("c");
}
if(S_ISBLK(buf.st_mode)){
printf("b");
}
if(S_ISFIFO(buf.st_mode)){
printf("p");
}
if(S_ISSOCK(buf.st_mode)){
printf("s");
}
// printf(" ");
int i;
for(i=8;i>=0;i--){
if(buf.st_mode & (1<<i)){
switch(i%3){
case 2:
printf("r");
break;
case 1:
printf("w");
break;
case 0:
printf("x");
break;
}
}else{
printf("-");
}
}
printf(" %d",(int)buf.st_size);
struct tm *t;
t = localtime(&buf.st_ctime);
printf(" %d-%d-%d %d:%d",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min);
printf(" chmod_t.c\n");
}
静态库
库的概念
-
库是一个二进制文件,包含的代码可被程序调用
-
标准C库、数学库、线程库……
-
库有源码,可下载后编译;也可以直接安装二进制包
-
linux库存放在这两个文件夹/lib /usr/lib
库的知识
- 库是事先编译好的,可以复用的代码。
- 在OS上运行的程序基本上都要使用库。使用库可以提高开发效率。
- Windows和Linux下库文件的格式不兼容
- Linux下包含静态库和共享库
静态库的特点
优点
- 编译(链接)时把静态库中相关代码复制到可执行文件中
- 程序中已包含代码,运行时不再需要静态库
- 程序运行时无需加载库,运行速度更快
缺点
- 占用更多磁盘和内存空间
- 静态库升级后,程序需要重新编译链接
静态库的创建
-
确定库中函数的功能、接口
-
编写库源码 如hello.c
#include <stdio.h>
void hello(void) {
printf(“hello world\n”);
return;
}
- 编译生成目标文件
目标文件为.o文件
$ gcc -c hello.c -Wall
- 创建静态库 如hello
库名字要以lib开头,后缀名为.a
$ ar -rsv libhello.a hello.o
ar 参数:
- c 禁止在创建库时产生的正常消息
- r 如果指定的文件已经存在于库中,则替换它
- s 无论 ar 命令是否修改了库内容都强制重新生成库符号表
- v 将建立新库的详细的逐个文件的描述写至标准输出
- q 将指定的文件添加到库的末尾
- t 将库的目录写至标准输出
- 查看库中符号信息
$nm libhello.a
hello.o:
0000000 T hello
U puts
- nm:显示指定文件中的符号信息
- -a 显示所有符号
- 编写应用程序 如test.c
#include <stdio.h>
void hello(void);
int main() {
hello();
return 0;
}
- 编译test.c 并链接静态库libhello.a
$ gcc -o test test.c -L. -lhello
- -L 表示库所在的路径
- -l 后面跟库的名称
动态库
动态库也叫共享库
动态库的特点
- 编译(链接)时仅记录用到哪个共享库中的哪个符号,不复制共享库中相关代码
- 程序不包含库中代码,尺寸小
- 多个程序可共享同一个库
- 程序运行时需要加载库
- 库升级方便,无需重新编译程序
- 使用更加广泛
动态库的创建
-
确定库中函数的功能、接口
-
编写库源码 如:hello.c bye.c
#include <stdio.h>
void hello(void) {
printf(“hello world\n”);
return;
}
#include <stdio.h>
void bye(void) {
printf(“bye\n”);
return;
}
- 编译生成目标文件
目标文件为.o文件
$ gcc -c -fPIC hello.c bye.c -Wall
- -fPIC 生成于位置无关的代码(动态库必须加他)
- 创建动态库 如common
库名字也是以lib开头,后缀名为.so
$ gcc -shared -o libcommon.so.1 hello.o bye.o
- 为共享库文件创建链接文件
创建链接文件的原因是很多库都是通过链接的形式来运行的
$ ln -s libcommon.so.1 libcommon.so
- 编写应用程序test.c
#include <stdio.h>
#include “common.h” //头文件和静态库不一样
int main() {
hello();
bye();
return 0;
}
- 编译test.c 并链接共享库libcommon.so
$ gcc -o test test.c -L. -lcommon
- -L 表示库所在的路径
- -l 后面跟库的名称
动态库找不到的解决办法
如果编译完直接运行会出现下面的错误
含义:可执行文件所使用的动态库找不到
$ ./test
./test: error while loading shared libraries: libcommon.so
cannot open shared object file : No such file or directory
这时候有三种解决办法
方法一:
把库拷贝到/usr/lib和/lib目录下
方法二(常用):
在LD_LIBRARY_PATH环境变量中添加库所在路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:你的动态库目录
如果只在命令行运行这个命令,新打开shell窗口就不行了,这时候可以在启动文件中创建环境
添加在~/.bashrc 文件里面
使用source ~/.bashrc 生效。
vim~/.bashrc
source ~/.bashrc
方法三:
添加/etc/ld.so.conf.d/*.conf文件,执行ldconfig刷新
查看可执行文件使用的动态库
ldd 命令 : ldd 你的可执行文件
库存在时:
root@haas-virtual-machine:/mnt/hgfs/share/newIOP# ldd test
linux-vdso.so.1 => (0x00007fff6548d000)
libmyheby.so => /mnt/hgfs/share/newIOP/day5/libmyheby.so (0x00007f5c89521000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5c89144000)
/lib64/ld-linux-x86-64.so.2 (0x000055fe52211000)
库不存在时:
root@haas-virtual-machine:/mnt/hgfs/share/newIOP/day5# ldd test
linux-vdso.so.1 => (0x00007ffcb652c000)
libmyheby.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbeeffaf000)
/lib64/ld-linux-x86-64.so.2 (0x0000561003c3b000)