第四章 文件与I/O(1)

文件与I/O

什么是I/O

  • 输入/输出是主存和外部设备之间拷贝数据的过程

    • 设备->内存 (输入操作)
    • 内存->设备 (输出操作)
  • 高级I/O

    • ANSI C提供的标准I/O库称为高级I/O,通常也称为带缓冲的I/O
  • 低级I/O

    • 通常也称为不带缓冲的I/O

文件描述符

ㅤ ㅤ对于Linux而言,所有对设备或文件的操作都是通过文件描述符进行的。

ㅤ ㅤ当打开或者创建一个文件的时候,内核向进程返回一个文件描述符(非负整数)。后续对文件的操作只需通过该文件描述符,内核记录有关这个打开文件的信息。

ㅤ ㅤ一个进程启动时,默认打开了3个文件,标准输入、标准输出、标准错误,对应文件描述符是0(STDIN_FILENO)、1(STDOUT_FILENO)、2(STDERR_FILENO),这些常量定义在<unistd.h>头文件中。

文件描述符 文件指针
STDIN_FILENO stdin
STDOUT_FILENO stdout
STDERR_FILENO stderr

文件描述符与文件指针转换

  • fileno:将文件指针转换为文件描述符
  • fdopen:将文件描述符转换为文件指针
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    //文件指针转文件描述符
    printf("fileno(stdin) = %d\n",fileno(stdin));
    printf("fileno(stdout) = %d\n",fileno(stdout));
    printf("fileno(stderr) = %d\n",fileno(stderr));

    //文件描述符转文件指针
    FILE * pf = NULL;
    pf = fdopen(STDOUT_FILENO, "w+");
    fprintf(pf,"%s\n","hello!");

    pf = fdopen(STDERR_FILENO, "w+");
    fprintf(pf,"%s\n","ERROR!");

    fclose(pf);

    return 0;
}

文件相关系统调用

open系统调用

ㅤ ㅤ有几种方法可以获得允许访问文件的文件描述符。最常用的是使用open()(打开)系统调用

函数原型
int open(const char *path, int flags);
参数
    path :文件的名称,可以包含(绝对和相对)路径
    flags:文件打开模式
返回值
    打开成功,返回文件描述符;
    打开失败,返回-1
  • 两个参数
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

//#define ERR_EXIT(m) (perror(m)),exit(EXIT_FAILURE)
#define ERR_EXIT(m) \
        do \
        { \
            perror(m); \
            exit(EXIT_FAILURE); \
        }while(0)

int main(void)
{
    int fd;
    fd = open("test.txt", O_RDONLY);
    if(fd == -1)
    {
        fprintf(stderr,"open error with errno = %d %s\n",errno,strerror(errno));
        ERR_EXIT("open");
    }
    if (fd == -1)
    {
        perror("open");
        exit(EXIT_FAILURE);
    }
    printf("open success\n");
    
    return 0;
}
  • 三个参数
函数原型
int open(const char *path, int flags,mode_t mode);
参数
    path :文件的名称,可以包含(绝对和相对)路径
    flags:文件打开模式
    mode:  用来规定对该文件的所有者,文件的用户组及系统中其他用户的访问权限
返回值
    打开成功,返回文件描述符;
    打开失败,返回-1
  • 文件权限
newnode = mode & ~umask
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#define ERR_EXIT(m) \
        do \
        {   \
            perror(m); \
            exit(EXIT_FAILURE); \
        }while(0)

int main(void)
{
    //如果文件存在,umask()无效
    umask(0);
    int fd;
    fd = open("test.txt", O_WRONLY | O_CREAT, 0666);
    if(fd == -1)
        ERR_EXIT("open");

    printf("open success\n");
    return 0;
}
  • 打开文件的方式
打开方式 描述
O_RDONLY 打开一个供读取的文件
O_WRONLY 打开一个供写入的文件
O_RDWR 打开一个可供读写的文件
O_APPEND 写入的所有数据将被追加到文件的末尾,多进程中每个进程都会更新文件位置指针
O_CLOEXEC 在执行新的进程时,文件会自动关闭
O_CREAT 打开文件,如果文件不存在则建立文件
O_EXCL 如果已经置O_CREAT且文件存在,则强制open()失败
O_TRUNC 在open()时,将文件的内容清空

所有这些标志值的符号名称可以通过#include<fcntl.h>访问

  • 访问权限
打开方式 描述
S_IRUSR 文件所有者的读权限位
S_IWUSR 文件所有者的写权限位
S_IXUSR 文件所有者的执行权限位
S_IRWXU S_IRUSR
S_IRGRP 文件用户组的读权限位
S_IWGRP 文件用户组的写权限位
S_IXGRP 文件用户组的执行权限位
S_IRWXG S_IRGRP
S_IROTH 文件其他用户的读权限位
S_IWOTH 文件其他用户的写权限位
S_IXOTH 文件其他用户的执行权限位
S_IRWXO S_IROTH

open调用的几点说明

  • 可以利用按位逻辑加(bitwise-OR)(|)对打开方式的标志值进行组合。
    • 如打开一个新文件:
    #define NEWFILE (O_WRONLY|O_CREAT|O_TRUNC)
    
  • 对访问权限位进行访问所用到的标识符,均可以通过
    • #include <sys/stat.h> 访问到,同样可以通过|运算来对访问权限进行组合
    #define MODE755 (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
    

close系统调用

ㅤ ㅤ为了重新利用文件描述符,用close()系统调用释放打开的文件描述符

函数原型:int close(int fd);
函数参数:
    fd :要关闭的文件的文件描述符
返回值
    如果出现错误,返回-1
    调用成功返回0

一个进程能打开的最大文件描述符的个数

ulimit -n

一个系统能够支持打开文件的最大个数

//这个值和内存有关系,内存越大,值越大
cat /proc/sys/fs/file-max 

creat系统调用

ㅤ ㅤ为了维持与早期的 UNIX 系统的向后兼容性,Linux 也提供可选的创建文件的系统调用,它称为 creat()。

函数原型:
    int creat(const char *path, mode_t mode); 
参数
    path :文件的名称,可以包含(绝对和相对)路径
    mode:  用来规定对该文件的所有者,文件的用户组及系统中其他用户的访问权限
返回值
    打开成功,返回文件描述符;
    打开失败,返回-1

ㅤ ㅤ在UNIX的早期版本中,open() 系统调用仅仅存在两个参数的形式。如文件不存在,它就不能打开这些文件。文件的创建则由单独的系统调用 creat() 完成。在 Linux 及所有 UNIX 的近代版本中,creat() 系统调用是多余的。

fd = creat(file, mode);
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);

creat() 完全等价于近代的 open() 调用

posted @ 2019-08-06 19:00  sfdevs  阅读(59)  评论(0)    收藏  举报