1 Linux 文件读写


前言 (含目录)


Linux默认文件描述符个数为 1024
可用命令查看

ulimit -n

前三个默认已占用

// stdin
#define STDIN_FILENO	0;
// stdout
#define STDOUT_FILENO	1;
// stderr
#define STDERR_FILENO	2;
/**
 * @author IYATT-yx
 * @brief 读取一个文件,并写入另外一个文件(不存在则创建)
 */
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    
    
    if (argc != 3)
    {
    
    
        printf("请指定两个参数,分别为 [源文件] [目标文件]\n");
        return -1;
    }
    
    // 打开源文件,若执行失败,open内部会设置 errno 值,并返回 -1
    // perrno根据 errno 的值,输出对应错误信息
    int fdRead = open(argv[1], O_RDONLY);
    if (fdRead == -1)
    {
    
    
        perror("read file");
        return -1;
    }

    // 打开或不存在就创建将要写入的目标文件
    // 指定生成的文件权限为 0664 ,实际文件的权限为 0664 & ~umask
    int fdWrite = open(argv[2], O_WRONLY | O_CREAT, 0664);
    if (fdWrite == -1)
    {
    
    
        perror("write file");
        return -1;
    }

    char buf[4096];
    ssize_t len;

    // 从文件描述符 fdRead 读取 buf 容量大小的数据到 buf 中, 返回值为实际读取的数据长度, 返回 0 读完,返回 -1 失败
    while ((len = read(fdRead, buf, sizeof(buf))) > 0)
    {
    
    
        // 将 buf 中 len 长度的数据写入 fdWrite 文件描述符对应打开的文件, 返回 -1 代表失败!
        ssize_t ret = write(fdWrite, buf, (size_t)len);
        if (ret == -1)
        {
    
    
            perror("write");
            return -1;
        }
    }

    // 关闭文件描述符
    close(fdRead);
    close(fdWrite);
}

移动 文件指针 到头部

lseek(fd, 0, SEEK_SET);

获取文件指针当前位置

off_t idx = lseek(fd, 0, SEEK_CUR);

获取文件长度

off_t len = lseek(fd, 0. SEEK_END);

文件拓展 (比如可以在开始下载时,创建一个空白文件,并根据要下载的文件大小来拓展本地下载文件为相同的大小来占位,下载时再依次从头开始替换拓展填充的数据)

// 拓展 1KB 大小
off_t size = 1024;
lseek(fd, size, SEEK_END);
// 拓展后进行write才有效,写入内容任意,比如这里以空格结尾
const char *str = " ";
write(fd, str, 1);



/**
 * @author IYATT-yx
 * @brief 阻塞读终端
 */
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    
    
    char buf[5];
    ssize_t len = read(STDIN_FILENO, buf, 5);
    if (len == -1)
    {
    
    
        perror("open STDIN_FILENO");
        return -1;
    }
    write(STDOUT_FILENO, buf, (size_t)len);
}

编译执行这个程序后,终端会等待用户输入,并一直停在read函数处,直到输入内容按下回车,将输入内容的前五个(不足5个字符则为实际输入个数)读入buf,下一步执行write将buf的内容打印输出到终端.
当输入的字符在read设定的5个之内时可能没有异样,但是如果输入的数据超过5个,可能会看到另一番现象.前面5个字符会被正常输出,后面的字符会在命令提示符后显示,并被当作命令执行.而这种现象的原因:当执行这里的程序时,程序作为前台,终端切换到后台,而这个程序只获取前5个字符,并将获取到的字符输出,完成以后程序结束,终端切为前台,并将执行程序时输入超出的字符接受,同时执行.
在这里插入图片描述

/**
 * @author IYATT-yx
 * @brief 非阻塞读终端
 */
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdbool.h>
#include <errno.h>

int main(void)
{
    
    
    int fdRead = open("/dev/tty", O_RDONLY | O_NONBLOCK);
    if (fdRead == -1)
    {
    
    
        perror("open /dev/tty");
        return -1;
    }
    char buf[4];
    ssize_t len;
    while (true)
    {
    
    
        len = read(fdRead, buf, sizeof(buf));
        if (len == -1)
        {
    
    
            if (errno == EAGAIN)
            {
    
    
                printf("请重试!\n");
                sleep(3);
                continue;
            }
            perror("read /dev/tty");
            return -1;
        }
        write(STDOUT_FILENO, buf, (size_t)len);
        close(fdRead);
        return 0;
    }
}

在非阻塞读终端时,在没有输入的情况下, 不会一直停在read处等待输入而是继续执行下去.

ps:
普通文件的属性默认不阻塞
终端设备,管道,套接字文件默认阻塞


复制文件描述符:
dup 函数: 返回新的文件描述符(最小的未被占用的)也指向原文件描述符指向的文件
dup2 函数: 可以自己指定新的文件描述符指向原文件描述符指向的文件

猜你喜欢

转载自blog.csdn.net/weixin_45579994/article/details/112690496
今日推荐