操作系统——文件的相关操作

10 篇文章 0 订阅
9 篇文章 0 订阅

文件的相关操作

一、文件同步

    1、在写入数据时,内存到磁盘之间有一块缓冲区,这种机制降低了磁盘读写次数、提高了读写效率

    2、但是这种机制带来的后果是磁盘的数据与实际写入的数据不匹配,系统提供了三个系统函数可以让缓冲区的数据立即写入到磁盘

    void sync(void);

    功能:立即把缓冲区中的数据同步到磁盘

    注意:并不会等待数据同步结束才返回,而是提交要同步的数据到写入队列中,就返回

    int fsync(int fd);

    功能:把指定文件的内容同步到磁盘

    注意:会等到完全写入磁盘后才返回

    int fdatasync(int fd);

    功能:把指定文件的内容同步到磁盘,只同步文件内容不同步文件属性

二、文件属性

    int stat(const char *pathname, struct stat *buf);

    功能:根据文件的路径获取文件属性

    buf:存储文件属性的结构体 是一个输出型参数

    int fstat(int fd, struct stat *buf);

    功能:根据文件描述获取文件属性

    int lstat(const char *pathname, struct stat *buf)

    功能:根据文件的路径获取软链接文件属性

    struct stat {

        dev_t     st_dev;  //   设备ID

        ino_t     st_ino;  //   inode节点号

        mode_t    st_mode; //   文件类型和权限

        nlink_t   st_nlink; //  硬链接数

        uid_t     st_uid;   // 用户ID

        gid_t     st_gid;   // 组ID

        dev_t     st_rdev;  //  特殊设备ID号

        off_t     st_size;  //  总字节数

        blksize_t st_blksize;  // IO块字节数

        blkcnt_t  st_blocks;   // 占用512Bblock块数量

        struct timespec st_atim;  // 最后访问时间

        struct timespec st_mtim;  // 最后内容修改时间

        struct timespec st_ctim;  // 最后状态修改时间

    };

    st_mode:

        文件类型:

        S_IFMT     0170000   获取文件类型的掩码

        S_IFSOCK   0140000   socket文件

        S_IFLNK    0120000   软链接文件

        S_IFREG    0100000   普通文件

        S_IFBLK    0060000   块设备文件

        S_IFDIR    0040000   目录文件

        S_IFCHR    0020000   字符设备文件

        S_IFIFO    0010000   管道文件

    上面类型判断在POSIX中定义了以下函数进行类型判断

        S_ISREG(st_mode)    是普通文件

        S_ISDIR(m)          是目录文件

        S_ISCHR(m)          字符设备文件

        S_ISBLK(m)          块设备文件

        S_ISFIFO(m)         管道文件

        S_ISLNK(m)          软链接文件

        S_ISSOCK(m)         socket文件

    st_mode包含的权限信息:

        S_IRWXU     00700   用户自己的权限掩码

        S_IRUSR     00400       读

        S_IWUSR     00200       写

        S_IXUSR     00100       执行

        S_IRWXG     00070   测试组权限的掩码

        S_IRGRP     00040       读

        S_IWGRP     00020       写

        S_IXGRP     00010       执行

        S_IRWXO     00007   测试其他用户权限的掩码

        S_IROTH     00004       读

        S_IWOTH     00002       写

        S_IXOTH     00001       执行

   

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <pwd.h>

#include <grp.h>

#include <time.h>

//  显示文件类型

void file_type(mode_t mode)

{

    switch(mode & S_IFMT)

    {

        case S_IFSOCK:  printf("s"); break;

        case S_IFLNK:   printf("l"); break;

        case S_IFREG:   printf("-"); break;

        case S_IFBLK:   printf("b"); break;

        case S_IFDIR:   printf("d"); break;

        case S_IFCHR:   printf("c"); break;

        case S_IFIFO:   printf("p"); break;

    }

}

//  显示文件权限

void file_mode(mode_t mode)

{

    printf("%c",mode & S_IRUSR ?'r':'-');  

    printf("%c",mode & S_IWUSR ?'w':'-');  

    printf("%c",mode & S_IXUSR ?'x':'-');  

    printf("%c",mode & S_IRGRP ?'r':'-');  

    printf("%c",mode & S_IWGRP ?'w':'-');  

    printf("%c",mode & S_IXGRP ?'x':'-');  

    printf("%c",mode & S_IROTH ?'r':'-');  

    printf("%c",mode & S_IWOTH ?'w':'-');  

    printf("%c ",mode & S_IXOTH ?'x':'-');  

}

//  显示用户名

void user_name(uid_t uid)

{

    struct passwd* pw = getpwuid(uid);

    printf("%s ",pw->pw_name);

}

//  显示组名

void group_name(gid_t gid)

{

    struct group* gp = getgrgid(gid);

    printf("%s ",gp->gr_name);

}

//  获取最后访问时间

void access_time(time_t time)

{

    struct tm* t = localtime(&time);

    printf("%d月  %d %d:%d ",

        t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min);

}

void list_file_stat(const char* path)

{

    //  获取文件属性

    struct stat buf;

    if(stat(path,&buf))

    {

        perror("stat");

        return;

    }

    //  显示文件类型

    file_type(buf.st_mode);

    //  显示文件权限

    file_mode(buf.st_mode);

    //  显示目录层数

    printf("%d ",S_ISDIR(buf.st_mode)?2:1);

    //  显示用户名

    user_name(buf.st_uid);

    //  显示组名

    group_name(buf.st_gid);

    //  显示字节数

    printf("%lu ",buf.st_size);

    //  显示最后访问时间

    access_time(buf.st_atim.tv_sec);

    //  显示文件名

    printf("%s\n",path);

}

int main(int argc,const char* argv[])

{

    list_file_stat("01stat.c");

}

三、文件的权限

    int access(const char *pathname, int mode);

    功能:测试当前用户对文件的权限

    pathname:文件的路径

    mode:想要测试的权限

        F_OK    文件是否存在

        R_OK    读权限

        W_OK    写权限

        X_OK    执行权限

    返回值:存在返回0,不存在返回-1

#include <stdio.h>

#include <unistd.h>

int main(int argc,const char* argv[])

{

    printf("%d\n",access("01stat.c",F_OK));

    printf("%d\n",access("01stat.c",R_OK));

    printf("%d\n",access("01stat.c",W_OK));

    printf("%d\n",access("01stat.c",X_OK));

}

    int chmod(const char *pathname, mode_t mode);

    功能:根据路径修改文件权限

    mode:由三位八进制数组成的权限码

        0644    普通文件

        0755    目录文件/可执行文件

#include <stdio.h>

#include <sys/stat.h>

int main(int argc,const char* argv[])

{

    printf("%d\n",chmod("01stat.c",0777));  

}

    int fchmod(int fd, mode_t mode);

    功能:根据文件描述符修改文件权限

四、权限屏蔽码

    如果我们不想让新创建的文件拥有某种权限,则可以设置权限过滤,记录在权限屏蔽码中

    权限屏蔽码对chmod命令和函数是无效的

    通过命令 umask 查看当前终端的权限屏蔽码

        1、通过 umask 0xxx 设置当前终端的权限屏蔽码

        2、函数修改

            mode_t umask(mode_t mask);

            mask:想要设置的权限屏蔽码

            返回值:旧的权限屏蔽码

    注意:通过命令、函数修改权限屏蔽码,只会在当前终端生效,如果关闭后会恢复为默认的

五、修改文件的大小

    int truncate(const char *path, off_t length);

    功能:根据文件路径修改文件长度

    length:想要修改的字节数

#include <stdio.h>

#include <unistd.h>

#include <sys/types.h>

int main(int argc,const char* argv[])

{

    printf("%d\n",truncate("test.txt",30));

}

    int ftruncate(int fd, off_t length);

    功能:根据文件描述符修改文件长度

    length:想要修改的字节数

    练习1:实现一个函数,可以删除文件的[n,m)个字节

    int cut_file(const char* path,size_t n,size_t m);

    // 读写打开文件

    // 从m读到buf

    // 从buf写到n

    // 更新m n 继续读写

    // 读完 相当于 从m挪到n 把后面删除

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

int cut_file(const char* path,size_t n,size_t m)

{

    int fd = open(path,O_RDWR);

    if(0 > fd)

    {

        perror("open");

        return -1;

    }

   

    //  计算原文件字节数

    int len = lseek(fd,0,SEEK_END);

    if(m > len) m = len;

    if(n >= m) return -1;

   

    //  计算出删除后文件字节数

    len -= (m-n);

   

    //  从m开始数据向前移动

    char buf[256] = {};

    lseek(fd,m,SEEK_SET);

    int ret = 0;

    while(ret = read(fd,buf,sizeof(buf)))

    {

        //  写入到文件的n位置

        lseek(fd,n,SEEK_SET);

        write(fd,buf,ret);

        //  更新m n

        m += ret;

        n += ret;

        lseek(fd,m,SEEK_SET);

    }

    //  删除末尾多余数据

    ftruncate(fd,len);

    close(fd);

}

int main(int argc,const char* argv[])

{

    cut_file("test.txt",3,80);

}

六、文件删除和重命名

    int remove(const char *pathname);

    功能:标准库中的删除文件、空目录的函数

         底层调用了unlink

#include <stdio.h>

int main(int argc,const char* argv[])

{

    printf("%d\n",remove("dir"));

}

    int unlink(const char *pathname);

    功能:删除文件

   

    int rename(const char *oldpath,const char *newpath);

    功能:重命名、移动文件

#include <stdio.h>

int main(int argc,const char* argv[])

{

    printf("%d\n",rename("tt.c","./dir/t.c"));

}

七、链接文件

    Linux文件系统会有两个主要的分区:

        inode信息块:默认128B,记录文件权限、大小、所有者、修改时间等

        block数据块:默认4k,记录了文件名和数据信息

        每个文件必须拥有唯一一个inode以及若干个block块,读写文件需要借助目录的block中记录的文件名和inode号找到该文件的inode,

        通过inode读取block

    什么是软硬链接文件?

        硬链接:硬链接文件没有自己的inode和block,只是在不同目录下复制了一份源文件的inode信息,通过inode信息访问源文件的block

        软链接:软链接会建立自己的新的inode和block,软链接的block存储的是源文件的inode信息、文件名

        区别:

            1、删除源文件,只是删除了源文件的inode信息,硬链接不受影响,而软链接无法访问

            2、对于一个文件而言,硬链接数删除为0时,文件才被真正的删除  

            3、当修改硬链接文件的内容,源文件也会被修改

            4、硬链接不能链接目录,软链接可以

            5、硬链接不能跨文件系统、软链接可以

   int link(const char *oldpath,const char *newpath);

   功能:创建硬链接文件

    int symlink(const char *target,const char *linkpath);

    功能:创建软链接文件

     ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);

     功能:读取软链接文件链接路径

#include <stdio.h>

#include <unistd.h>

int main(int argc,const char* argv[])

{

    //printf("%d\n",link("/home/ubuntu/随机.c","li.c"));  

//  printf("%d\n",symlink("/home/ubuntu/随机.c","syli.c"));

    char buf[256] = {};

    readlink("syli.c",buf,sizeof(buf));

    printf("%s\n",buf);

}

八、目录操作

    int mkdir(const char *pathname, mode_t mode);

    功能:创建目录

    mode:权限,必须要执行权限才能访问目录

   

    int rmdir(const char *pathname);

    功能:删除空目录

    char *getcwd(char *buf, size_t size);

    功能:获取当前工作目录,相当于pwd

    buf:存储结果的内存

    size:buf的大小

    返回值:buf的地址 方便链式调用

    int chdir(const char *path);

    功能:根据路径字符串修改工作路径

    int fchdir(int fd);

    功能:根据文件描述符修改工作路径

    DIR *opendir(const char *name);

    功能:打开目录文件,返回目录流结构体指针

    DIR *fdopendir(int fd);

    功能:打开目录文件,返回目录流结构体指针

    struct dirent *readdir(DIR *dirp);

    功能:从目录流中读取一条记录信息,该条信息记录了目录中一个文件的信息

        struct dirent {

            ino_t   d_ino;   // inode号

            off_t   d_off;   // 下一条信息的偏移量

            unsigned short d_reclen; //当前信息的长度

            unsigned char  d_type; // 文件的类型

            char           d_name[256]; // 文件名

        };

#include <stdio.h>

#include <dirent.h>

int main(int argc,const char* argv[])

{

    DIR* dir = opendir(".");    

    if(NULL == dir)

    {

        perror("opendir");

        return -1;

    }

    for(struct dirent* d=readdir(dir); d; d=readdir(dir))

    {

        if('.' != d->d_name[0])

            printf("%s\n",d->d_name);  

    }

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xiaoyu1381

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

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

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

打赏作者

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

抵扣说明:

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

余额充值