一文掌握「文件 I/O」 常用函数

文件操作函数

open

    //头文件
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>

    // 打开一个已经存在的文件
    int open(const char *pathname, int flags);
        参数:
            - pathname:要打开的文件路径
            - flags:对文件的操作权限设置还有其他的设置
              O_RDONLY,  O_WRONLY,  O_RDWR  这三个设置是互斥的
        返回值:返回一个新的文件描述符,如果调用失败,返回-1

    errno:属于Linux系统函数库,库里面的一个全局变量,记录的是最近的错误号。

    #include <stdio.h>
    void perror(const char *s);作用:打印errno对应的错误描述
        s参数:用户描述,比如hello,最终输出的内容是  hello:xxx(实际的错误描述)
    
    // 创建一个新的文件
    int open(const char *pathname, int flags, mode_t mode);
        参数:
            - pathname:要创建的文件的路径
            - flags:对文件的操作权限和其他的设置
                - 必选项:O_RDONLY,  O_WRONLY, O_RDWR  这三个之间是互斥的
                - 可选项:O_CREAT 文件不存在,创建新文件
            - mode:八进制的数,表示创建出的新的文件的操作权限,比如:0775
            最终的权限是:mode & ~umask
            0777   ->   111111111
        &   0775   ->   111111101
        ----------------------------
                        111111101
        按位与:0和任何数都为0
        umask的作用就是抹去某些权限。

        flags参数是一个int类型的数据,占4个字节,32位。
        flags 32个位,每一位就是一个标志位。


read

#include <unistd.h>
    ssize_t read(int fd, void *buf, size_t count);
        参数:
            - fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
            - buf:需要读取数据存放的地方,数组的地址(传出参数)
            - count:指定的数组的大小
        返回值:
            - 成功:
                >0: 返回实际的读取到的字节数
                =0:文件已经读取完了
            - 失败:-1 ,并且设置errno

write

#include <unistd.h>
    ssize_t write(int fd, const void *buf, size_t count);
        参数:
            - fd:文件描述符,open得到的,通过这个文件描述符操作某个文件
            - buf:要往磁盘写入的数据,数据
            - count:要写的数据的实际的大小
        返回值:
            成功:实际写入的字节数
            失败:返回-1,并设置errno

一个栗子:

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

int main() {

    // 1.通过open打开english.txt文件
    int srcfd = open("english.txt", O_RDONLY);
    if(srcfd == -1) {
        perror("open");
        return -1;
    }

    // 2.创建一个新的文件(拷贝文件)
    int destfd = open("cpy.txt", O_WRONLY | O_CREAT, 0664);
    if(destfd == -1) {
        perror("open");
        return -1;
    }

    // 3.频繁的读写操作
    char buf[1024] = {0};
    int len = 0;
    while((len = read(srcfd, buf, sizeof(buf))) > 0) {
        write(destfd, buf, len);
    }

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


    return 0;
}

lseek

   标准C库的函数
   #include <stdio.h>
   int fseek(FILE *stream, long offset, int whence);

   Linux系统函数
   #include <sys/types.h>
   #include <unistd.h>
   off_t lseek(int fd, off_t offset, int whence);
       参数:
           - fd:文件描述符,通过open得到的,通过这个fd操作某个文件
           - offset:偏移量
           - whence:
               SEEK_SET
                   设置文件指针的偏移量
               SEEK_CUR
                   设置偏移量:当前位置 + 第二个参数offset的值
               SEEK_END
                   设置偏移量:文件大小 + 第二个参数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;
}

stat, lstat函数

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

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

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

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

int main() {

    struct stat statbuf;

    int ret = stat("a.txt", &statbuf);

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

    printf("size: %ld\n", statbuf.st_size);


    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("a.txt", F_OK);
    if(ret == -1) {
        perror("access");
    }

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

    return 0;
}

chmod

#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
    作用:修改文件的权限
    参数:
         - pathname: 需要修改的文件的路径
         - mode:需要修改的权限值,八进制的数
    返回值:成功返回0,失败返回-1

栗子:

#include <sys/stat.h>
#include <stdio.h>
int main() {

    int ret = chmod("a.txt", 0777);

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

    return 0;
}

chown

int chown(const char *pathname, uid_t owner, gid_t group);
    作用:更改文件的所有者

truncate

 #include <unistd.h>
 #include <sys/types.h>
 int truncate(const char *path, off_t length);
      作用:缩减或者扩展文件的尺寸至指定的大小
       参数:
           - path: 需要修改的文件的路径
          - length: 需要最终文件变成的大小
      返回值:
          成功返回0, 失败返回-1

栗子:

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

int main() {

    int ret = truncate("b.txt", 5);

    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("aaa", "bbb");

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

    return 0;
}

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("aaa", 0777);

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

    return 0;
}

chdir 和 getcwd

    #include <unistd.h>
    int chdir(const char *path);
        作用:修改进程的工作目录
        比如在/home/nowcoder 启动了一个可执行程序a.out, 进程的工作目录 /home/nowcoder
        参数:
            path : 需要修改的工作目录
        返回值:
            成功返回0, 失败返回-1

    #include <unistd.h>
    char *getcwd(char *buf, size_t size);
        作用:获取当前工作目录
        参数:
            - buf : 存储的路径,指向的是一个数组(传出参数)
            - size: 数组的大小
        返回值:
            返回指向的一块内存,这个数据就是第一个参数

栗子:

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

int main() {

    // 获取当前的工作目录
    char buf[128];
    getcwd(buf, sizeof(buf));
    printf("当前的工作目录是:%s\n", buf);

    // 修改工作目录
    int ret = chdir("/home/nowcoder/Linux/lesson13");
    if(ret == -1) {
        perror("chdir");
        return -1;
    } 

    // 创建一个新的文件
    int fd = open("chdir.txt", O_CREAT | O_RDWR, 0664);
    if(fd == -1) {
        perror("open");
        return -1;
    }

    close(fd);

    // 获取当前的工作目录
    char buf1[128];
    getcwd(buf1, sizeof(buf1));
    printf("当前的工作目录是:%s\n", buf1);
    
    return 0;
}

目录遍历函数

opendir

    // 打开一个目录
    #include <sys/types.h>
    #include <dirent.h>
    DIR *opendir(const char *name);
        参数:
            - name: 需要打开的目录的名称
        返回值:
            DIR * 类型,理解为目录流
            错误返回NULL

readdir

    // 读取目录中的数据
    #include <dirent.h>
    struct dirent *readdir(DIR *dirp);
        - 参数:dirp是opendir返回的结果
        - 返回值:
            struct dirent,代表读取到的文件的信息
            读取到了末尾或者失败了,返回NULL
结构体参数:     
struct dirent
    {
    // 此目录进入点的inode
    ino_t d_ino;
    // 目录文件开头至此目录进入点的位移
    off_t d_off;
    // d_name 的长度, 不包含NULL字符
    unsigned short int d_reclen;
    // d_name 所指的文件类型
    unsigned char d_type;
    // 文件名
    char d_name[256];
    };
    
d_type:
    DT_BLK - 块设备
    DT_CHR - 字符设备
    DT_DIR - 目录
    DT_LNK - 软连接
    DT_FIFO - 管道
    DT_REG - 普通文件
    DT_SOCK - 套接字
    DT_UNKNOWN - 未知

closedir

    // 关闭目录
    #include <sys/types.h>
    #include <dirent.h>
    int closedir(DIR *dirp);

栗子:

#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int getFileNum(const char * path);

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

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

    int num = getFileNum(argv[1]);

    printf("普通文件的个数为:%d\n", num);

    return 0;
}

// 用于获取目录下所有普通文件的个数
int getFileNum(const char * path) {

    // 1.打开目录
    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 += getFileNum(newpath);
        }

        if(ptr->d_type == DT_REG) {
            // 普通文件
            total++;
        }


    }

    // 关闭目录
    closedir(dir);

    return total;
}

文件描述符相关函数

dup

    #include <unistd.h>
    int dup(int oldfd);
        作用:复制一个新的文件描述符
        fd=3, int fd1 = dup(fd),
        fd指向的是a.txt, fd1也是指向a.txt
        从空闲的文件描述符表中找一个最小的,作为新的拷贝的文件描述符

栗子:

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

int main() {

    int fd = open("a.txt", O_RDWR | O_CREAT, 0664);

    int fd1 = dup(fd);

    if(fd1 == -1) {
        perror("dup");
        return -1;
    }

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

    close(fd);

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

    close(fd1);

    return 0;
}

dup2

    #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 <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.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;
    }

    // 通过fd1去写数据,实际操作的是1.txt,而不是2.txt
    char * str = "hello, dup2";
    int len = write(fd1, str, strlen(str));

    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, ...);
    参数:
        fd : 表示需要操作的文件描述符
        cmd: 表示对文件描述符进行如何操作
            - F_DUPFD : 复制文件描述符,复制的是第一个参数fd,得到一个新的文件描述符(返回值)
                int ret = fcntl(fd, F_DUPFD);

            - F_GETFL : 获取指定的文件描述符文件状态flag
              获取的flag和我们通过open函数传递的flag是一个东西。

            - F_SETFL : 设置文件描述符文件状态flag
              必选项:O_RDONLY, O_WRONLY, O_RDWR 不可以被修改
              可选性:O_APPEND, O_NONBLOCK
                O_APPEND 表示追加数据
                NONBLOK 设置成非阻塞
        
        阻塞和非阻塞:描述的是函数调用的行为

栗子:

#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
    int flag = fcntl(fd, F_GETFL);
    if(flag == -1) {
        perror("fcntl");
        return -1;
    }
    flag |= O_APPEND;   // flag = flag | O_APPEND

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

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

    close(fd);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

海岸星的清风

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

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

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

打赏作者

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

抵扣说明:

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

余额充值