Linux文件操作

文件操作

Linux中有一句非常经典的话—一切皆文件,Linux将一切硬件都通过文件的方式进行处理,所以对于文件的操作是一门必备学习。

在这里插入图片描述

每一个进程中会建立一个虚拟地址空间,对文件等进行控制,每个文件进程创建的文件占用一个文件描述符,内核空间中有一个PCB(进程控制块)其中有文件描述符,每个进程打开一个文件描述符会占用一个位置,每次占用的位置都是从最小的位置开始,前三个位置的状态被系统占用默认打开状态。

struct stat {
   dev_t     st_dev;     /* ID of device containing file 文件的设备编号*/
   ino_t     st_ino;     /* inode number 节点*/
   mode_t    st_mode;    /* protection 文件的类型与存取权限*/
   nlink_t   nlink;      /* number of hard links 链接到该文件的影链接数目*/
   user_t    st_uid;     /* user ID of owner 用户ID*/
   gid_t     st_gid;     /* group ID of owner 组ID*/
   dev_t     st_rdev;    /* device ID (if special file) 设备文件的设备编号*/
   off_t     st_size;    /* total size, in bytes 文件字节数(文件大小)*/
   blksize_t st_blksize; /* blocksize for file system I/O 块大小*/
   blkcnt_t  st_blocks;  /* number of 512B blocks allocated 块数*/
   time_t    st_atime;   /* time of last access 最后一次访问时间*/
   time_t    st_mtime;   /* time of last modification 最后一次修改时间*/
   time_t    st_ctime;   /* time of last status change 组后一次改变时间(改变属性)*/
};

struct stat是一个文件块中的信息,用函数 stat可以获取路径下的文件信息

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *path, struct stat *buf);
    作用:查看文件的信息
           -path:操作文件的路径
           -buf: 结构体变量,传出参数,用于保存获取到的文件的信息
    返回值:
          成功:返回0
          失败:返回-1, 设置errno 

int lstat(const char *path, struct stat *buf);
    作用:查看软连接文件的信息
           -path:操作文件的路径
           -buf: 结构体变量,传出参数,用于保存获取到的文件的信息
    返回值:
          成功:返回0
          失败:返回-1, 设置errno 

在这里插入图片描述

每一个文件都有自己的文件类型符st_mode,通过操作这个文件描述符可以改变文件的类型和权限等参数。

r-代表可读权限,w-代表可写权限,x代表可执行权限

前三位是其他组,其后三位是Group和Uer,通过设置各个组不同的权限可以使得文件被访问的状态。

- S_IFSOCK 0140000 套接字

- S_IFLNK 0120000 符号链接(软链接)

- S_IFREG 0100000 普通文件

- S_IFBLK 0060000 块设备

- S_IFDIR 0040000 目录

- S_IFCHR 0020000 字符设备

- S_IFIFO 0010000 管道

- S_IFMT 0170000 掩码

(st_mode & S_IFMT) == S_IFREG

setGID – 设置组id

setUID – 设置用户id

Sticky – 粘住位

ls-l模拟

//模拟实现ls -l功能
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <string.h>
#include <time.h>

int main (int argc, char* argv[]) {
    if (argc < 2) {
        printf("%s filename\n", argv[0]);
        return -1;
    }

    //通过stat函数获取用户传入的文件信息
    struct stat st;
    int ret = stat (argv[1], &st);
    if (ret == -1) {
        perror("stat");
        return -1;
    }

    //获取文件类型和文件权限
    char perms[11] = {0};   //  用于保存

    switch(st.st_mode & S_IFMT) {
        case S_IFLNK:
            perms[0] = 'l';
            break;
        case S_IFDIR:
            perms[0] = 'd';
            break;
        case S_IFBLK:
            perms[0] = 'b';
            break;
        case S_IFCHR:
            perms[0] = 'c';
            break;
        case S_IFSOCK:
            perms[0] = 's';
        case S_IFIFO:
            perms[0] = 'p';
        default:
            perms[0] = '?';
    }

    //判断文件的访问权限

    //文件所有者
    perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
    perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
    perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';

    //文件所在组
    perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
    perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
    perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';

    //其他人
    perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
    perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
    perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';

    //硬连接数
    int linkNum = st.st_nlink;
    
    //文件所有者
    char* fileUser = getpwuid(st.st_uid)->pw_name;

    //文件所在组
    char* fileGrp = getgrgid(st.st_gid)->gr_name;

    //文件大小
    long int fileSize = st.st_size;

    //获取修改时间
    char* time = ctime(&st.st_mtime);
    char mtime[512];
    strncpy(mtime, time, strlen(time) - 1);

    char buf[1024];
    sprintf(buf, "%s %d %s %s %d %s %S", perms, linkNum, fileUser, fileGrp, fileSize, mtime,argv[1]); 

    printf("%s", buf);

    return 0;
}

lseek

标准C库 lseek

#include <stdio.h>

int fseek(FILE \*stream, long offset, int whence);

linux lseek

#include <sys/types.h>

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

参数:

​ - fd:文件描述符,通过open得到的,通过fd操作文件

​ - offset: 偏移量

​ - whence:

​ SEEK_SET

​ The offset is set to offset bytes.

​ 设置文件指针的偏移量

​ SEEK_CUR

​ The offset is set to its current location plus offset bytes.

​ 设置文件指针的偏移量:从当前位置 + 第二个参数offset的值

​ SEEK_END

​ The offset is set to the size of the file plus offset bytes.

​ 设置偏移量:文件大小 + 第二个参数offset的值

​ 返回值:返回文件指针的位置

作用:

​ 1.移动文件指针到头文件

​ lseek(fd,0,SEEK_SET);

​ 2.获取文件指针的位置

​ lseek(fd,0,SEEK_CUR);

​ 3.获取文件长度

​ lseek (fd, 0, SEEK_END);

​ 4.拓展文件的长度,当前文件10b->110b,增加100

​ lseek(fd, 100, SEEK_END);

​ 注意:需要写一次数据,增加的长度才会生效

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdio.h>

int main () {
    int fd = open("hello.txt",O_RDWR);

    if (fd == -1) {
        perror("open");
        return -1;
    }

    int ret = lseek(fd, 100, SEEK_END);
    if (ret == -1) {
        perror("lseek");
        return -1;
    }

    write(fd, " ",1);

    close(fd);
    return 0;
}

open

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char \*pathname, int flags);

int open(const char \*pathname, int flags, mode_t mode);

--必选项 O_RDONLY, O_WRONLY, or O_RDWR

–可选项 O_CREAT 文件不存在,创建新文件

​ mode :八进制的数,表示创建处的新的文件的操作权限

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int fd = open("create.txt", O_RDWR | O_CREAT,0777);
    if (fd == -1) {
        perror("open");
    }
    close(fd);
    return 0;
}

read/write

#include <unistd.h>

ssize_t read(int fd, void \*buf, size_t count);

​ 参数:

​ -fd :文件描述符,通过文件描述符操作文件

​ -buf:需要读取存放的地方,数组的地址(传出参数)

​ -count: 指定的数组的大小

​ 返回值:ssize_t

​ -成功:

​ >0: 返回实际读取到的字节数

​ ==0: 文件已经读取完了

​ -失败:

​ -1, 并且设置errno

#include <unistd.h>

ssize_t write(int fd, const void \*buf, size_t count);

​ 参数:

​ - fd:文件描述符,通过文件描述符操作文件

​ -buf: 要往磁盘写入的数据

​ -count:要写的数据的实际大小

​ 返回值:

​ 成功:实际写入的字节数

​ 失败:返回-1,并设置errno

int main() {
      // 通过open打开文件
      int srcfd = open("file.txt",O_RDONLY);
      if (srcfd == - 1) {
          perror("open");
          return -1;
      }
      //创建一个新的文件(拷贝文件)
      int destfd = open("copy.txt", O_WRONLY | O_CREAT, 0664);
      if (destfd == -1) {
          perror("open");
          return -1;
      }
      //频繁的读写操作
      char buf[1023] = {0};
      int len = 0;

      while(len = read(srcfd, buf, sizeof(buf)) > 0) {
          write(destfd, buf, len);
      } 


      
      //关闭文件
      close(destfd);
      close(srcfd);

      return 0; 
}

access

#include <unistd.h>

int access(const char *pathname, int mode);
作用:判断某个文件是否有某个权限,或者判断文件是否存在
参数:
-pathname:判断文件的路径
-mode:
R_OK:判断是否有读权限
W_OK:判断是否有写权限
X_OK:判断是否有执行权限
F_OK:判断分件是否存在
返回值: 成功返回0,失败返回-1

#include <unistd.h>
#include <stdio.h>

int main () {
    int ret = access("hello.txt",F_OK);
    if (ret == -1) {
        perror("access");
        return -1;
    }

    printf("文件存在!!");

    return 0;
}

chmod

#include <sys/stat.h>

int chmod(const char \*path, mode_t mode);

​ 作用:修改文件的权限

​ 参数:

​ -pathname:需要修改的文件的路径

​ -mode:需要修改的权限值,八进制的值

#include<sys/stat.h>
#include<stdio.h>

int main () {

    int ret = chmod("hello.txt", 0775);

    if (ret == -1) {
        perror("chmod");
        return -1;
    }

    return 0;
}

truncate

#include <unistd.h>

#include <sys/types.h>

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

​ 作用:缩减或者扩展文件的尺寸到指定的大小

​ 参数:

​ -path:需要修改的文件的路径

​ -length: 需要最终文件变成的大小

#include <unistd.h>
#include <sys/types.h>

int main () {

    int ret = truncate("hello.txt",20);
    
    if (ret == -1) {
        perror("truncate");
        return -1;
    }

    return 0;
}

rename

#include <stdio.h>

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

​ 作用:改变文件名称

#include <stdio.h>

int main () {
    int ret = rename("hello.txt","abc");

    if (ret == -1) {
        perror("rename");
        return -1;
    }
}

chdir/getcwd

#include <unistd.h>

int chdir(const char *path);

作用:修改当前进程的目录(在/code下启动了一个可执行程序a.o,进程的工作的路径就是/code)

参数:

​ path:需要修改到的目的工作目录

#include <unistd.h>

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

作用:获取当前工作目录

参数:

​ buf:存储的路径,指向的是一个数组----也是传出的参数

​ size:数组的大小

#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/type.h>
#include <fcntl.h>

int main () {
      //获取当前的工作目录
      char buf[128];
      getcwd(buf, sizeof(buf));
      printf("当前工作的目录是:%s\n", buf);
      
      //修改工作目录
      int ret = chdir("...");
      if (ret == -1) {
        perror("chdir");
        return -1;
      }


}

mkdir

#include <sys/stat.h>

#include <sys/types.h>

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

作用:创建一个目录

参数:

​ pathname:创建目录的路径

​ mode:权限,八进制的数

返回值:

​ 成功返会0,失败返回-1

#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>

int main () {
    int ret = mkdir("abc", 0777);

    if (ret == -1) {
        perror("mkdir");
        return -1;
    }

    return 0;
}

opendir/closedir/readdir

//打开一个目录

#include <sys/types.h>

#include <dirent.h>

qDIR *opendir(const char *name);

​ 参数:

​ name:需要打开的目录名称

​ 返回值:

​ Dir* 类型,理解为目录流

//读取目录中的内容

#include <dirent.h>

struct dirent *readdir(DIR *dirp);

​ 参数:dirp是opendir返回的结果

​ 返回值:

struct dirent,返回读到的文件信息

​ 读取到末尾或者失败,会返回NULL

#include <sys/types.h>

#include <dirent.h>

int closedir(DIR \*dirp);

struct dirent {
 ino_t          d_ino;       /* inode number 此目录进入点的inode*/
 off_t          d_off;       /* not an offset; see NOTES 
 目录文件开头至此目录进入点的位移*/
 unsigned short d_reclen;    /* length of this record 
 d_name 的长度, 不包含NULL字符*/
 unsigned char  d_type;      /* type of file; not supported by all file     system types 
 d_name 所指的文件类型*/
 char           d_name[256]; /* filename 文件名*/
};

//读取某个目录下所有的普通文件的个数
int main (int argc, char* argv[]) {

    if (argc < 2) {
        printf("%s path\n", argv[0]);
        return -1;
    }

    int num = gerFileNum(argv[1]);
    printf("普通文件个数为:%d",num);
    return 0;
}

int gerFileNum(const char* path) {
    //打开目录
    DIR* dir = opendir(path);

    if (dir == NULL) {
        perror("opendir");
        exit(0);
    }

    struct dirent* ptr;
    int total = 0;
    while((ptr = readdir(dir)) != NULL) {
        //获取名称
        char* dname = ptr->d_name;
        //忽略掉.和..
        if (strcmp(dname, ".") == 0 || strcmp(dname, "..") == 0) {
            continue;
        }
        
        //判断是普通文件还是目录
        if (ptr->d_type == DT_DIR) {
            char newpath[256];
            sprintf(newpath, "%s/%s", path, dname);
            total += gerFileNum(newpath);
        }

        if (ptr->d_type == DT_REG) {
            //普通文件
            total++;
        }
    }
    //关闭目录
    closedir(dir);

    return total;
}

dup/dup2

#include <unistd.h>

int dup(int oldfd);

​ 作用:复制一个新的文件描述符

fd = 3, int fd1 = dup(fd)

​ fd指向的是a.txt,fd1也是指向a.txt

​ 从空闲的(文件描述符表)中的位置找到一个最小的作为文件描述符

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>


int main () {
    int fd = open("a.txt", O_RDWR | O_CREAT, 0664);
    if (fd == -1) {
        perror("open");
        return -1;
    }
    
    int fd1 = dup(fd);
    if (fd1 == -1) {
        perror("dup");
        return -1;
    }
    printf("fd: %d, fd1: %d\n", fd, fd1);

    close(fd);

    char* tmp = "hello, world";
    int ret = write(fd1, tmp, sizeof(tmp));
    if (ret == -1) {
        perror("write");
        return -1;
    }
    close(fd1);

    return 0;

}

#include <unistd.h>

int dup2(int oldfd, int newfd);

​ 作用:重定向文件描述符

​ oldfd指向a.txt , newfd指向b.txt

​ 调用函数成功后:newfd和b.txt做close,newfd指向了a.txt

​ oldfd必须是一个有效的文件描述符

​ oldfd和newfd值相同,相当于什么都没有做

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main () {
    int fd = open("1.txt", O_RDWR | O_CREAT, 0664);
    if (fd == -1) {
        perror("open");
        return -1;
    }

    int fd1 = open("2.txt", O_RDWR | O_CREAT, 0664);
    if (fd1 == -1) {
        perror("open");
        return -1;
    }

    printf("fd: %d fd1: %d\n", fd, fd1);

    int fd2 = dup2(fd, fd1);
    if (fd2 == -1) {
        perror("dup2");
        return -1;
    }
    
    char* tmp = "hello, dup2";
    int len = write(fd1, tmp, strlen(tmp));

    if (len == -1) {
        perror("write");
        return -1;
    }

    printf("fd: %d, fd1: %d, fd2: %d\n",fd,fd1,fd2);
    close(fd);
    close(fd1);

    return 0;

}

fcntl

#include <unistd.h>

#include <fcntl.h>

int fcntl(int fd, int cmd, ... /arg/ );

参数:

​ fd: 表示需要操作的文件描述符

​ cmd: 表示对文件描述符进行如何操作

​ - F_DUPFD:复制文件描述符,复制的是fd

​ - F_GETFL:获取指定的文件描述符状态flag

​ flag就是open函数转递的flag如O_CREAT等

​ -F_SETFL:设置文件描述符文件状态flag

​ 必选项:O_RDONLY,O_WRONLY,O_RDWR不可被修改

​ 可选项:O_APPEND,O_NONBLOCK

​ O_APPEND表示追加数据

​ O_NONBLOCK 设置成非阻塞

#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>

int main () {
    //1.复制文件描述符
    //int fd = open("1.txt",O_RDONLY);
    //int ret = fcntl(fd, F_DUPFD);

    //2.修改或者获取文件状态flag

    int fd = open("1.txt", O_RDWR);
    if (fd == -1) {
        perror("open");
        return -1;
    }
    //修改文件描述符状态的flag,给flag加入O_APPEND这个标记
    int flag = fcntl(fd, F_GETFL);
    flag |= O_APPEND;  
    
    int ret = fcntl(fd, F_SETFL, flag);

    char* str = " world";
    write(fd, str, strlen(str));
    close(fd);



    return 0;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值