系统IO和重定向

C库I/O函数复习

比较常用的几个C库函数有fopen()fwrite()fread()fprintf()fscanf()等,这里挑几个复习,其他函数可以查看man手册。

#include <stdio.h>
#include <errno.h>
#include <string.h>

int main()
{
    FILE *fp = NULL;
    //FILE文件流指针——C库IO接口句柄。
    size_t ret;
    fp = fopen("./c_io.txt", "w+");
    //FILE *fopen(const char *path, const char *mode);
    //  path 路径
    //  mode 打开方式
    //  r   只读打开已经存在的文件
    //  r+  读写打开已经存在的文件
    //  w   只写打开文件,文件不存在则创建,存在则长度截断为0
    //  w+  读写打开文件,文件不存在则创建,存在则长度截断为0
    //      若文件不存在,则创建文件,创建的文件权限默认为664
    //  a   追加模式(只写)打开文件,从文件末尾开始写入数据
    //  a+  读写(追加),文件读写位置刚打开的时候在起始位置,当写入的
    //      时候文件读写位置移动到文件末尾
    //      若文件不存在,则创建文件,创建的文件权限默认为664
    if (fp == NULL) {
        perror("fopen error");
        return -1;
    }

    size_t = fwrite("hello there!\n", 11, 1, fp);
    //size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
    //ptr    读取数据存入的目标地址
    //size   一次需要读取的字节
    //nmemb  读取的次数
    //stream 文件指针
    if (ret == 0) {
        perror("fwrite error");
    }

    if (feof(fp) == 1) {
        printf("file pointer in the end of file!\n");
    }


    char buff[1024] = {0};

    fseek(fp, 0, SEEK_SET);
    //fseek 
    //  SEEK_SET    从文件起始位置开始偏移
    //  SEEK_CUR    从当前读写位置开始偏移
    //  SEEK_END    从文件末尾位置开始偏移
    ret = fread(buff, 1, 11, fp);
    //size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    //ptr    读取数据存入的目标地址
    //size   一次需要读取的字节
    //nmemb  读取的次数
    //stream 文件指针

    if (ret == 0) {
        perror("read error");
    }
    printf("buff->%s\n", buff);

    //fseek(fp, 0, SEEK_END);
    //fprintf(fp, "%s-%d\n", "bit", 666);
    fclose(fp);
    return 0;
}

系统调用I/O

几个知识点

文件描述符

一个int整数,每个文件描述符都对应一个文件 标准输入对应0,标准输出对应1,标准错误输出对应2
POSIX 定义了 STDIN_FILENO、STDOUT_FILENO 和 STDERR_FILENO 来代替 0、1、2

文件描述符如何分配

0、1、2已经被标准输入、输出、错误输出,接下来的文件将优先分配当前进程最小可用文件描述符
例如已经分配到10,3对应文件被关闭,下一个打开的文件将优先分配3

文件留置针

文件留置针是一个结构体,这个结构体中有一个成员就是文件描述符

库函数和系统调用接口的关系

上下级调用关系 下面介绍系统调用I/O的几个基本函数

进程如何通过一个数字来操作文件呢?

这个数字是进程pcb中file_struct这个结构体中描述文件描述信息的结构体数组的下标 操作系统就可以通过数字下表找到对应文件的信息,来完成对这个文件的操作

函数接口

open

int open(const char *pathname, int flags, mode_t mode);
  pathname:要打开的文件路径
  flags:标志选项
  必选项:(这个三个选项互相冲突,只能选择其中一个)
          O_RDONLY    只读
          O_WRONLY    只写
          O_RDWR      读写
      非必选项:
          O_CREAT     若文件存在在打开,不存在则创建
          O_EXCL      与O_CREAT同用时,若文件存在则报错
          O_TRUNC     若文件存在则将文件长度截断为0
          O_APPEND    追加(针对写入)
  mode:若文件不存在需要创建的时候,用于指定创建的文件权限
  返回值:
      成功 :非负整数(文件描述符),后续操作都通过描述符完成
      失败 :-1

write

ssize_t write(int fd, const void *buf, size_t count);
  从buf中向fd所代表的文件写入count个字节的数据
  返回实际的写入长度,出错返回-1

read

ssize_t read(int fd, void *buf, size_t count);
  从fd所代表的文件中读取count字节长度的数据放到buf中
  返回实际读取的数据长度,出错返回-1

lseek

off_t lseek(int fd, off_t offset, int whence);
    fd     文件描述符
    offset 偏移量
    whence 偏移位置
        SEEK_SET  从文件头部偏移
        SEEK_CUR  从当前位置偏移
        SEEK_END  从文件尾部偏移
    返回值:
        成功返回偏移量
        错误返回-1并将errno设置为错误码

代码

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

int main()
{
    umask(0);
    int fd;
    fd = open("./s_io.txt", O_RDWR | O_CREAT | O_APPEND, 0777);
    if (fd < 0)
    {
        perror("file open error");
        return -1;
    }

    char w_buff[1024] = "Hi jo, long time no see!";
    ssize_t w_len = write(fd, w_buff, strlen(w_buff));
    if (w_len < 0)
    {
        perror("file write error");
        return -1;
    }
    printf("write length:%ld\n", w_len);

    lseek(fd, 0, SEEK_SET);
    //读写位置跳转,从头开始偏移0个字节

    char r_buff[1024] = { 0 };
    ssize_t r_len = read(fd, r_buff, 1024);
    if (r_len < 0)
    {
        perror("file read error");
        return -1;
    }
    printf("read length:%ld\nread string->%s\n", r_len, r_buff);

    close(fd);
    return 0;
}

重定向

理解重定向前先看代码

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>

int main()
{
    int fd = 0;
    //关闭文件描述符为1的文件,新打开的文件将占据1号描述符
    close(1);
    fd = open("./redirect.txt", O_RDWR | O_CREAT | O_APPEND, 0644);
    if (fd < 0)
    {
        perror("Open file failed\n");
        return -1;
    }
    //printf本来应该输出到屏幕,看看结果如何
    printf("This is a file ostream redirect test\nFile fd -> %d\n", fd);
    fflush(stdout);
    close(fd);
    return 0;
}

看下运行结果
重定向
运行没有任何输出,但是查看redirect.txt却发现本来应该输出屏幕的内容输出到文件内了
为什么???
我们在前面说过文件描述符的0、1、2分别分配给了标准输入、标准输出和标准错误输出
我们关闭了文件描述符1,之后又打开了文件,按照文件描述符分配规则,优先分配最小的空闲文件描述符,因此1被分配给新打开的文件,此时如果输出,则输出到刚打开的文件中了
这里就是重定向的基本原理,linux下万物皆文件,所以重定向也是基于文件。

重定向应用

<输入重定向

标准输入重定向 <
原本从标准输入读取数据重定向文从其他文件读取数据

>和>>输出重定向

将原本要输出到标准输出的内容,重定向后输出到指定的其他文件

/dev/null是个黑洞文件,所有写入该文件的内容都会被丢弃
标准输出STDOUT为1,但是我们一般不写1,忽略1,所以看下面语句中有>/dev/null其实等同于1>/dev/null
2>&1相当于2号文件重定向到1号文件,也就是STDERR重定向到STDOUT

    ./test.exe 2>&1 >/dev/null
    //将标准错误输出重定向到标准输出,标准输出重定向到/dev/null
    //也就是只输出错误输出,不输出正确输出
    ./test.exe >/dev/null 2>&1
    //将标准输出重定向到/dev/null,标准错误输出重定向到标准输出
    //由于标准输出已经重定向,所以错误输出也重定向到/dev/null
    //不管正确还是错误输出均不输出
发布了89 篇原创文章 · 获赞 96 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/Boring_Wednesday/article/details/82503026