zoukankan      html  css  js  c++  java
  • Linux系统编程常用函数 (文件/目录)

    Lunix系统编程函数多且复杂,本文记录一下Linux系统编程最最常用的哪些函数以及这些函数的常见用法。当然本文不可能囊括所有,所以在编程时候最好的学习方法还是查看manpage,多看多写,熟能生巧。

    博主继续Linux编程不久,水平有限文章有错误还请各位不吝指出。废话不多说,开始咯。

    文件操作:

    Open函数:     所需头文件#include<sys/types.h>        #include<sys/stat.h>          #include<fcntl.h>

    int open(const char *pathname, int flags, mode_t mode);     函数作用是打开一个文件,pathname是要打开文件的"路径+名称",flags是打开方式,mode是文件权限(配合新建文件时候使用,会受umask影响)。

    其中flags的取值:O_RDONLY—只读打开、 Q_WRONLY—只写打开、O_RDWR—读、写打开 ;这三个变量只能指定一个 ;O_CREAT—若文件不存在,则创建它。需要使用mode(文件权限标志)选项,来指明新文件的访问权限 ;O_APPEND—追加写;O_TRUNC 如果此文件存在,而且为只读或只写成功打开,则将其长度截短为0。O_NONBLOCK 如果pathname指的是一个FIFO、一个块特殊文件或一个字符特殊文件,则此选择项为此文件的本次打开操作和后续的I/O操作设置非阻塞方式。O_NDELAY所产生的结果使I/O变成非阻塞模式(non-blocking),在读取不到数据或是写入缓冲区已满会马上return,而不会阻塞等待。

    返回值:成功则返回打开文件的描述符,失败则返回-1。
    文件标识符0、1、2分别代表标准输入、标准输出和标准错误输出,分别用常量STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO代替。

    Close函数

    int close(int fd);    与open相对应的,close是关闭文件函数,fd是想要关闭的文件描述符。这个函数几乎不会产生错误。

    Read函数:#include<unistd.h>

    ssize_t read(int fd, void *buf, size_t count);  函数作用是从文件中读取数据,fd是想从文件描述符为fd中读取,buf是要存放读入数据的缓冲区,count是缓冲区大小。

    返回值>0,实际读到的字节数,=0读到文件末尾对端关闭了,-1产生错误,看errno:

    EINTR 此调用被信号所中断。EAGAIN / EWOULDBLOCK 当使用不可阻断I/O 时(O_NONBLOCK),若无数据可读取则返回此值。EBADF 参数fd 非有效的文件描述词,或该文件已关闭。

    Write函数:#include<unistd.h>

    ssize_t write(int fd, const void *buf, size_t count);  与read相对于的,函数作用是写出数据。fd是写到文件描述符为fd的文件中,buf要把哪里缓冲区的数据写出,count是缓冲区大小。

    返回值:如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。

    Perror函数:#include <stdio.h>

    void perror(const char *s);  这个函数有关上面函数返回值时,多次提到的错误代码。它的作用是:先打印s指向的字符串,然后输出当前errno值所对应的错误提示信息,例如当前errno若为12,调用perror("ABC"),会输出"ABC: Cannot allocate memory"。

    此函数通常用于做很多判断上诉函数错误后的错误信息打印。

    相似功能的有:strerror 函数: char *strerror(int errnum);,它传入一个错误号errno,传出该错误号的对应错误详细。

    Fcntl函数

    int fcntl(int fd, int cmd, .../*arg*/....);  函数作用是:改变一个【已经打开】的文件的 访问控制属性。重点是F_GETFL和F_SETFL这两个的用法。

    改变某个打开文件的权限:int flags=fcntl (fd, F_GETFL);   --->      flags |= (想要的权限);  --->    fcntl(fd,F_SETFL,flags);

    Lseek函数

    Linux 中可使用系统函数 lseek 来修改文件偏移量(读写位置),每个打开的文件都记录着当前读写位置,打开文件时读写位置是 0,表示文件开头,通常读写多少个字节就会将读写位置往后移多少个字节。但是有一个例外,如果以 O_APPEND方式打开,每次写操作都会在文件末尾追加数据,然后将读写位置移到新的文件末尾。lseek和标准 I/O 库的 fseek 函数类似,可以移动当前读写位置(或者叫偏移量)。

    off_t lseek(int fd, off_t offset, int whence);  fd要偏移的文件描述符;offest偏移量;whence要从哪开始偏移,可以的取值:SEEK_SET:从文件头部开始偏移offset个字节。SEEK_CUR:从文件当前读写的指针位置开始,增加offset个字节的偏移量。SEEK_END文件偏移量设置为文件的大小加上偏移量字节。

    返回值:失败返回-1; 成功:返回的值是较文件起始位置向后的偏移量。

    两个特别注意:①lseek 允许超过文件结尾设置偏移量,文件会因此被拓展。②注意文件“读”和“写”使用同一偏移位置。

    lseek常见两个应用场景:①通过 lseek 获取文件的大小:len=lseek(fd, 0, SEEK_END);    ②使用 lseek 拓展文件:write 操作才能实质性的拓展文件。单 lseek 是不能进行拓展的。一般:write(fd, "a", 1);

    Stat函数

    int stat(const char *path, struct stat *buf);   获取文件属性,(从文件的inode 结构体中获取)。path是"路径名+文件名",stat是传出参数,返回path文件的文件属性结构体(这个可是编程是看manpage)。

    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;     //最后一次改变时间(指属性)
    };

    返回值:      执行成功则返回0,失败返回-1,错误代码存于errno。

    Lstat函数

    与stat函数一样,区别在于stat会符号穿透,而lstat不会穿透(即传入一个链接,不会解析原文件,而会解析成链接)

    Link函数

    int link(const char *oldpath, const char *newpath);   可以为已经存在的文件创建目录项(硬链接),path都是“路径+文件名”

    成功:0;失败:-1 设置 errno 为相应值

    Unlink函数

    int unlink(const char *pathname);  与link相对的,删除一个文件的目录项

    成功:0;失败:-1 设置 errno 为相应值

    注意 Linux 下删除文件的机制:不断将 st_nlink -1,直至减到 0 为止。无目录项对应的文件,将会被操作系统择机释放。(具体时间由系统内部调度算法决定)

    因此,我们删除文件,从某种意义上说, 只是让文件具备了被释放的条件。

    unlink 函数的特征:清除文件时,如果文件的硬链接数到 0 了,没有 dentry 对应,但该文件仍不会马上被释放。要等到所有打开该文件的进程关闭该文件,系统才会挑时间将该文件释放掉。

    Dup/Dup2函数

    这两个函数功能:都是文件描述符拷贝。重定向文件描述符指向。比较常用的是dup2:

    int dup2(int oldfd, int newfd);    文件描述符其实是一个bitmap,那么此函数的功能就是把bitmap中newfd位置指向oldfd位置,实现重定向。

    成功:返回一个新文件描述符;如果 oldfd 有效,则返回的文件描述符与 oldfd 指向同一文件。

    失败:如果 oldfd 无效,调用失败,关闭 newfd。返回-1,同时设置 errno 为相应值。

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<string.h>
     4 #include<fcntl.h>
     5 #include<unistd.h>
     6 
     7 void error_handling(char *message);
     8 
     9 //实现把argv[1]文件内容copy到argv[2]文件中
    10 int main(int argc,char *argv[])
    11 {
    12     char buf[1];
    13     int n=0;
    14     
    15     //open函数打开argv[1]文件并返回文件描述符
    16     int fd1=open(argv[1],O_RDONLY);
    17     if (fd1==-1) error_handling("open argv1 error");
    18 
    19     //同上
    20     int fd2=open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0664);
    21     if (fd2==-1) error_handling("open argv2 error");
    22 
    23     //copy主体
    24     while ((n=read(fd1,buf,1024))!=0) {    //read函数从fd1读取文件到buf,并返回读取大小
    25         if (n<0) {    //读完了
    26             perror("read error");
    27             break;
    28         }
    29         write(fd2,buf,n);    //把读取到的buf的内容写到fd2中
    30     }
    31 
    32     close(fd1);    //关闭fd1
    33     close(fd2);    //关闭fd2
    34 
    35     return 0;
    36 }
    37 
    38 void error_handling(char *message) {
    39     perror(message);
    40     exit(1);
    41 }
    上诉函数完成copy功能

    目录操作:

    Getcwd函数

    char *getcwd(char *buf, size_t size);  获取进程当前工作目录 (卷 3,标库函数)

    成功:buf 中保存当前进程工作目录位置。失败返回 NULL。

    Chdir函数

    int chdir(const char *path);  改变当前进程的工作目录

    成功:0;失败:-1 设置 errno 为相应值

    Opendir函数

    DIR *opendir(const char *name);  根据传入的目录名打开一个目录 (库函数) 

    成功返回指向该目录结构体指针,失败返回 NULL

    Readdir函数:

    struct dirent *readdir(DIR *dirp); 成功返回目录项结构体指针;失败返回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 */
      char d_name[256]; /* filename */  重点
    };

    Closedir函数

    int closedir(DIR *dirp);  关闭打开的目录  

    成功:0;失败:-1 设置 errno 为相应值

    在linux下遍历某一目录下内容LINUX下历遍目录的方法一般是这样的:打开目录->读取->关闭目录,相关函数是opendir -> readdir -> closedir ;

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include <sys/types.h>
     4 #include <sys/stat.h>
     5 #include <unistd.h>
     6 #include<string.h>
     7 #include<dirent.h>
     8 
     9 void read_dir(char *dir);
    10 
    11 void isFile(char *name) {
    12     int ret=0;
    13     struct stat sb;        //stat结构体
    14 
    15     ret = stat(name,&sb);
    16     if (ret==-1) {
    17         perror("stat error");
    18         return;
    19     }
    20 
    21     if (S_ISDIR(sb.st_mode)) {    //判断是否目录,是的话继续向下递归
    22         read_dir(name);
    23     }
    24 
    25     //不是目录,是文件,打印
    26     printf("%10s		%ld
    ",name,sb.st_size);
    27 
    28     return;
    29 }
    30 
    31 void read_dir(char *dir) {
    32     char path[256];
    33     DIR* dp;    //目录指针
    34     struct dirent *sdp;    // 目录项结构体
    35 
    36     dp=opendir(dir);    //open()函数打开目录,返回目录结构体
    37     if (dp==NULL) {
    38         perror("opendir error");
    39         return;
    40     }
    41 
    42     while ((sdp=readdir(dp))!=NULL) {
    43         if (strcmp(sdp->d_name,".")==0 || strcmp(sdp->d_name,"..")==0) continue;    //目录里有这两个东西,忽略避免死循环
    44 
    45 
    46         //拼接目录字符串并继续递归旧:目录+名字
    47         sprintf(path,"%s/%s",dir,sdp->d_name);
    48         isFile(path);
    49     }
    50 
    51     closedir(dp);    //open了一定记得close
    52 }
    53 
    54 
    55 int main(int argc,char *argv[])
    56 {
    57     if (argc==1)
    58         isFile(".");
    59     else
    60         isFile(argv[1]);
    61     return 0;
    62 }
    统计目录及其子目录中的普通文件的个数

    进程相关,进程间通信,线程相关,线程同步在另一篇文章:https://www.cnblogs.com/clno1/p/12935702.html

  • 相关阅读:
    CentOS 7源码安装zabbix
    CentOS 7 yum安装Zabbix
    Centos 7配置LAMP
    Oracle 12c RMAN备份文档
    Oracle 12c: RMAN restore/recover pluggable database
    Oracle 12c利用数据泵DataPump进行Oracle数据库备份
    EBS测试环境DataGuard配置
    oracle数据库将一列的值拼接成一行,并且各个值之间用逗号隔开
    ORA-19602: cannot backup or copy active file in NOARCHIVELOG mode
    rman输出日志的几种方法(转)
  • 原文地址:https://www.cnblogs.com/clno1/p/12935626.html
Copyright © 2011-2022 走看看