玩命加载中 . . .

1-文件操作相关函数


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
============================================

#include <unistd.h>
int close(int fd);
// 关闭指定的文件描述符
============================================ 

#include <stdio.h>
void perror(const char *s);
// 打印errno对应的错误描述

打开a.txt文件

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

int main() {

    int fd = open("a.txt", O_RDONLY);
    if (fd == -1) {
        perror("open");
    }
    close(fd);  // 关闭文件
    return 0;
}

创建文件

int open(const char *pathname, int flags, mode_t mode);
// 可以创建文件
- pathname: 文件路径
- flags: 文件的权限设置,必选,互斥
    - O_RDONLY, O_WRONLY, or O_RDWR (必选,互斥)
    - O_CREAT
- mode: 设置文件访问权限的初始值,八进制数,如0775,最终的权限是 mode&~umask
umask: 002, ~umask=0775
第三个参数是在第二个参数中有O_CREAT时才作用,如果没有,则第三个参数可以忽略
  • 文件权限。r:可读,w:可写,x:可执行
  • 三个一组,第一组为当前用户,第二组为用户所在组,第三组是其他组

创建一个create.txt文件

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

read

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
- fd: 文件描述符,通过open得到
- buf: 读取文件存放的地方,数组的地址,传出参数
- count: 数组大小
// 返回值:成功返回读取到的字节数,0表示到了文件末尾,-1表示出错

write

#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
- fd: 文件描述符
- buf: 要写入的数据
- count: 要写的数据的大小
// 成功返回写入的字节数,0表示没有内容写了,失败返回-1

用read和write实现文件拷贝

int main() {

    int srcfd = open("e.txt", O_RDONLY);
    if (srcfd == -1) {
        perror("open");
        return -1;
    }

    int destfd = open("cpy.txt", O_WRONLY | O_CREAT, 0664);
    if (destfd == -1) {
        perror("open");
        return -1;
    }

    char buf[1024] = {0};
    int len = 0;
    while ((len = read(srcfd, buf, sizeof(buf))) > 0) {
        printf("read %d bytes\n", len);
        write(destfd, buf, len);
    }

    close(srcfd);
    close(destfd);
    return 0;
}

lseek

#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
- 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. 拓展文件长度
lseek(fd, 100, SEEK_END);   // 从文件末尾拓展100字节

C库里面的类似

#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
- stream: FILE文件指针

拓展hello.txt文件

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

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
// 获取文件信息
- pathname: 文件路径
- statbuf: 保存文件信息,传出参数
// 成功返回0,失败返回-1,设置错误号

struct stat {
    dev_t     st_dev;       /* 块设备号(ID) */
    ino_t     st_ino;       /* inode结点号,文件属性信息所存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操作时,块的大小(一般是512或1024) */
    blkcnt_t  st_blocks;    /* 块的索引号 */                        
    time_t    st_atime;     /* 最后一次访问时间,read*/
    time_t    st_mtime;     /* 最后一次修改时间,write */
    time_t    st_ctime;     /* 最后一次属性修改的时间,如权限被修改,文件所有者(属主)被修改 */
};

文件类型信息包含在结构体st_mode成员中,以下这些宏的参数都是st_mode,也就是说通过st_mode成员可以判断文件类型,或者通过st_mode&S_IFMT的结果判断

S_ISREG(m)      是否为普通文件
S_ISDIR(m)      是否为目录
S_ISCHR(m)      是否为字符设备
S_ISBLK(m)      是否为块设备
S_ISFIFO(m)     是否为FIFO(命名管道文件,用于进程通信)
S_ISLNK(m)      是否为符号链接
S_ISSOCK(m)     是否为套接字

st_mode的0-8位保存文件的访问权限

st_mode 权限
S_IRUSR 用户读
S_IWUSR 用户写
S_IXUSR 用户执行
S_IRGRP 组读
S_IWGRP 组写
S_IXGRP 组执行
S_IROTH 其他读
S_IWOTH 其他写
S_IXOTH 其他执行
int lstat(const char *pathname, struct stat *statbuf);
// 获取软连接本身的文件信息
ln -s a.txt b.txt   // 创建一个软连接b.txt
// lrwxrwxrwx b.txt -> a.txt

stat查看文件大小

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

int main() {
    struct stat statbuf;
    int ret = lstat("b.txt", &statbuf);
    printf("size: %ld\n", statbuf.st_size);
    return 0;
}

stat实现ls -a

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <string.h>

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

    struct stat st;
    int ret = stat(argv[1], &st);

    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_IFREG:
        perms[0] = '-'; // 普通文件
        break;
    case S_IFBLK:
        perms[0] = 'b';
        break;
    case S_IFCHR:
        perms[0] = 'c';
        break;
    case S_IFSOCK:
        perms[0] = 's';
        break;
    case S_IFIFO:
        perms[0] = 'p';
        break;
    default:
        perms[0] = '?';
        break;
    }

    // 文件权限
    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;  // 用户id
    char *filegrp = getgrgid(st.st_gid)->gr_name;   // 组id

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

    char *time = ctime(&st.st_mtim.tv_sec);

    char mtime[512] = {0};
    strncpy(mtime, time, strlen(time) - 1);

    char buf[1024];

    sprintf(buf, "%s %d %s %s %ld %s %s", perms, linkNum, fileuser, filegrp, fileSize, mtime, argv[1]);

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

    return 0;
}

dup

拷贝文件描述符

#include <unistd.h>
int dup(int oldfd);
- oldfd: 要拷贝的文件描述符
- 返回值: 新的文件描述符
int main() {

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

    int fd1 = dup(fd);  // 拷贝文件描述符
    if (fd1 == -1) {
        perror("open");
        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

重定向文件描述符

int dup2(int oldfd, int newfd);

newfd关闭原来的文件,然后指向oldfd的文件,oldfd要有效
操作newfd就相当于操作oldfd

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);

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

    int fd2 = dup2(fd, fd1);
    if (fd2 == -1) {
        perror("dup2");
        return -1;
    }

    // 现在fd和fd1都指向1.txt
    char *str = "hello, world";
    int ret = write(fd1, str, strlen(str));
    if (ret == -1) {
        perror("write");
        return -1;
    }

    printf("fd: %d, fd1: %d, fd2: %d\n", fd, fd1, fd2); // fd: 3, fd1: 4, fd2: 4

    close(fd);
    close(fd1);

    return 0;
}

fcntl

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... );
- fd: 表示需要操作的文件描述符
- cmd: 表示对文件描述符进行何种操作
    - F_DUPFD: 复制文件描述符,复制fd,结果返回
    - F_GETFL: 获取指定文件描述符文件状态flag
        flag和通过open函数传递的flag是一个东西
    - F_SETFL: 设置文件描述符文件状态flag
        必选项: O_RDONLY, O_WRONLY, O_RDWR
        可选项: O_APPEND, O_NONBLOCK(设置成非阻塞)
int ret = fcntl(fd, F_DUPFD);   // 复制fd
int main() {

    int fd = open("1.txt", O_RDWR); // 打开文件

    int flag = fcntl(fd, F_GETFD);  // 获取原先的文件描述符
    flag |= O_APPEND;   // 添加追加flag
    int ret = fcntl(fd, F_SETFL, flag); // 设置为新的flag

    char *str = "hello";
    write(fd, str, strlen(str));
    close(fd);
    return 0;
}

文章作者: kunpeng
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kunpeng !
  目录