目录操作和库的使用

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下包含静态库和共享库

静态库的特点

优点

  • 编译(链接)时把静态库中相关代码复制到可执行文件中
  • 程序中已包含代码,运行时不再需要静态库
  • 程序运行时无需加载库,运行速度更快

缺点

  • 占用更多磁盘和内存空间
  • 静态库升级后,程序需要重新编译链接

静态库的创建

  1. 确定库中函数的功能、接口

  2. 编写库源码 如hello.c

#include <stdio.h>
void hello(void) {
    printf(“hello world\n”);
    return;
}
  1. 编译生成目标文件

目标文件为.o文件

$ gcc -c hello.c -Wall
  1. 创建静态库 如hello

库名字要以lib开头,后缀名为.a

$ ar -rsv libhello.a hello.o

ar 参数:

  • c 禁止在创建库时产生的正常消息
  • r 如果指定的文件已经存在于库中,则替换它
  • s 无论 ar 命令是否修改了库内容都强制重新生成库符号表
  • v 将建立新库的详细的逐个文件的描述写至标准输出
  • q 将指定的文件添加到库的末尾
  • t 将库的目录写至标准输出
  1. 查看库中符号信息
$nm libhello.a

hello.o:
0000000 T hello
        U puts
  • nm:显示指定文件中的符号信息
  • -a 显示所有符号
  1. 编写应用程序 如test.c
#include <stdio.h>
void hello(void);  

int main() {
    hello();
    return 0;
}
  1. 编译test.c 并链接静态库libhello.a
$ gcc -o test test.c -L. -lhello
  • -L 表示库所在的路径
  • -l 后面跟库的名称

动态库

动态库也叫共享库

动态库的特点

  • 编译(链接)时仅记录用到哪个共享库中的哪个符号,不复制共享库中相关代码
  • 程序不包含库中代码,尺寸小
  • 多个程序可共享同一个库
  • 程序运行时需要加载库
  • 库升级方便,无需重新编译程序
  • 使用更加广泛

动态库的创建

  1. 确定库中函数的功能、接口

  2. 编写库源码 如: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;
}
  1. 编译生成目标文件

目标文件为.o文件

$ gcc -c -fPIC hello.c bye.c -Wall
  • -fPIC 生成于位置无关的代码(动态库必须加他)
  1. 创建动态库 如common

库名字也是以lib开头,后缀名为.so

$ gcc -shared -o libcommon.so.1 hello.o bye.o    
  1. 为共享库文件创建链接文件

创建链接文件的原因是很多库都是通过链接的形式来运行的

$ ln -s libcommon.so.1 libcommon.so
  1. 编写应用程序test.c
#include <stdio.h>
#include “common.h”  //头文件和静态库不一样

int main() {
    hello();
    bye();
    return 0;
}
  1. 编译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)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深センのHZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值