📜  C中的输入输出系统调用创建,打开,关闭,读取,写入

📅  最后修改于: 2021-05-25 22:30:21             🧑  作者: Mango

重要术语

什么是文件描述符?
文件描述符是整数,用于唯一标识进程的打开文件。

文件描述符表:文件描述符表是整数数组索引的集合,这些整数数组索引是文件描述符,其中元素是指向文件表条目的指针。操作系统中为每个进程提供了一个唯一的文件描述符表。

文件表条目:文件表条目是打开文件的内存中替代结构,在进程请求打开文件时创建,并且这些条目保持文件位置。

标准文件描述符:当任何进程启动时,该进程文件描述符表的fd(文件描述符)将自动打开0、1、2(默认情况下)这3个fd引用文件表条目中的每一个,它们分别名为/ dev / tty

/ dev / tty :终端的内存中替代
终端:组合键盘/视频屏

从stdin读取=>从fd 0读取:每当我们从键盘写入任何字符时,它都会通过fd 0从stdin读取并保存到名为/ dev / tty的文件中。
写入stdout =>写入fd 1 :每当我们看到视频屏幕上的任何输出时,它都来自名为/ dev / tty的文件,并通过fd 1写入屏幕中的stdout。
写入stderr =>写入fd 2 :我们看到视频屏幕出现任何错误,这也是从该文件通过fd 2在屏幕中写入stderr的结果。

I / O系统调用

基本上共有5种类型的I / O系统调用:

  1. 创建:用于创建一个新的空文件。
    Syntax in C language: 
    int creat(char *filename, mode_t mode)
    
      范围 :
    • filename:您要创建的文件的名称
    • mode:表示新文件的权限。
      返回值:

    • 返回第一个未使用的文件描述符(通常在进程中首次使用creat时为3,因为保留了0、1、2 fd)
    • 错误时返回-1
      在OS中的运作方式
    • 在磁盘上创建新的空文件
    • 创建文件表条目
    • 设置第一个未使用的文件描述符以指向文件表条目
    • 返回使用的文件描述符,失败时返回-1
  2. open :用于打开文件以进行读取,写入或两者兼而有之。
    Syntax in C language 
    #include
    #include
    #include   
    int open (const char* Path, int flags [, int mode ]); 
    

    参数

    • 路径:您要使用的文件的路径
      • 当您不在文件的同一目录中时,请使用以“ /”开头的绝对路径。
      • 当您在文件的同一目录中工作时,请使用相对路径,该路径仅是带有扩展名的文件名。
    • 标志:您喜欢如何使用
      • O_RDONLY :只读; O_WRONLY :只写; O_RDWR :读和写; O_CREAT :如果不存在则创建文件; O_EXCL :如果已经存在则阻止创建
      在OS中的运作方式
    • 在磁盘上查找现有文件
    • 创建文件表条目
    • 设置第一个未使用的文件描述符以指向文件表条目
    • 返回使用的文件描述符,失败时返回-1
    // C program to illustrate
    // open system call
    #include
    #include
    #include
    extern int errno;
    int main()
    {     
        // if file does not have in directory 
        // then file foo.txt is created.
        int fd = open("foo.txt", O_RDONLY | O_CREAT); 
          
        printf("fd = %d/n", fd);
          
        if (fd ==-1)
        {
            // print which type of error have in a code
            printf("Error Number % d\n", errno); 
              
            // print program detail "Success or failure"
            perror("Program");                 
        }
        return 0;
    }
    

    输出:

    fd = 3
    
  3. close:告诉操作系统您已经完成了文件描述符,然后关闭fd指向的文件。
    Syntax in C language
    #include 
    int close(int fd); 
    
      范围
    • fd:文件描述符
      返回
    • 成功时为0
    • -1表示错误。
      它在操作系统中的工作方式
    • 销毁文件描述符表的元素fd引用的文件表条目
      –只要没有其他过程指向它!
    • 将文件描述符表的元素fd设置为NULL
    // C program to illustrate close system Call
    #include
    #include 
    int main()
    {
        int fd1 = open("foo.txt", O_RDONLY);
        if (fd1 < 0) 
        {
            perror("c1");
            exit(1);
        }
        printf("opened the fd = % d\n", fd1);
          
        // Using close system Call
        if (close(fd1) < 0) 
        {
            perror("c1");
            exit(1);
        } 
        printf("closed the fd.\n");
    }
    

    输出:

    opened the fd = 3
    closed the fd.
    
    // C program to illustrate close system Call
    #include
    #include
    int main()
    {
        // assume that foo.txt is already created
        int fd1 = open("foo.txt", O_RDONLY, 0); 
        close(fd1);
          
        // assume that baz.tzt is already created
        int fd2 = open("baz.txt", O_RDONLY, 0); 
          
        printf("fd2 = % d\n", fd2);
        exit(0);
    } 
    

    输出:

    fd2 = 3
    

    此处,在此代码中,首先open()返回3,因为在创建主进程时, stdinstdoutstderr已经采用了fd 0、1、2 。因此,文件描述符表中的第一个未使用的文件描述符为3 。之后,在close()系统调用中释放了这3个文件描述符,然后将3个文件描述符设置为null 。因此,当我们调用第二个open()时,第一个未使用的fd也是3 。因此,该程序的输出为3

  4. 读取:从文件描述符fd指示的文件中,read()函数将cnt字节的输入读取到由buf指示的存储区中。成功的read()将更新文件的访问时间。
    Syntax in C language 
    size_t read (int fd, void* buf, size_t cnt);  
    
      参数
    • fd:文件描述符
    • buf:缓冲区,用于从中读取数据
    • cnt:缓冲区的长度
      返回:实际读取了多少个字节
    • 返回成功读取的字节数
    • 到达文件末尾时返回0
    • 错误返回-1
    • 信号中断时返回-1
      重要事项
    • 由于溢出, buf需要指向长度不小于指定大小的有效内存位置。
    • fd应该是从open()返回的有效文件描述符,以执行读取操作,因为如果fd为NULL,则读取应生成错误。
    • cnt是请求的读取字节数,而返回值是实际读取的字节数。同样,有时读取系统调用读取的字节数应少于cnt。
    // C program to illustrate
    // read system Call
    #include
    #include 
    int main()
    {
      int fd, sz;
      char *c = (char *) calloc(100, sizeof(char));
      
      fd = open("foo.txt", O_RDONLY);
      if (fd < 0) { perror("r1"); exit(1); }
      
      sz = read(fd, c, 10);
      printf("called read(% d, c, 10).  returned that"
             " %d bytes  were read.\n", fd, sz);
      c[sz] = '\0';
      printf("Those bytes are as follows: % s\n", c);
    }
    

    输出:

    called read(3, c, 10).  returned that 10 bytes  were read.
    Those bytes are as follows: 0 0 0 foo.
    

    假设foobar.txt由6个ASCII字符“ foobar”组成。那么以下程序的输出是什么?

    // C program to illustrate 
    // read system Call 
    #include 
    #include 
    #include
    #include
      
    int main() 
    { 
        char c; 
        int fd1 = open("sample.txt", O_RDONLY, 0); 
        int fd2 = open("sample.txt", O_RDONLY, 0); 
        read(fd1, &c, 1); 
        read(fd2, &c, 1); 
        printf("c = %c\n", c); 
        exit(0); 
    } 
    

    输出:

    c = f
    

    描述符fd1fd2每个都有自己的打开文件表条目,因此每个描述符对于foobar.txt都有其自己的文件位置。因此,从FD2读读取foobar.txt的第一个字节,并且输出为c = F,而不是C = O。

  5. 写:将bnt中的cnt字节写入与fd相关联的文件或套接字。 cnt不应大于INT_MAX(在limits.h头文件中定义)。如果cnt为零,则write()仅返回0,而不会尝试任何其他操作。
    #include 
    size_t write (int fd, void* buf, size_t cnt); 
    
      参数
    • fd:文件描述符
    • buf:将数据写入的缓冲区
    • cnt:缓冲区的长度
      返回:实际写入了多少个字节
    • 返回成功写入的字节数
    • 到达文件末尾时返回0
    • 错误返回-1
    • 信号中断时返回-1
      重要事项
    • 该文件需要打开才能进行写操作
    • buf的长度必须至少等于cnt所指定的长度,因为如果buf的大小小于cnt,则buf会导致溢出。
    • cnt是请求写入的字节数,而返回值是实际写入的字节数。当fd要写入的字节数少于cnt时,会发生这种情况。
    • 如果write()被信号中断,则结果是以下之一:
      -如果write()尚未写入任何数据,则返回-1并将errno设置为EINTR。
      -如果write()已成功写入某些数据,则它将返回其被中断之前写入的字节数。
    // C program to illustrate
    // write system Call
    #include
    #include 
    main()
    {
      int sz;
      
      int fd = open("foo.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
      if (fd < 0)
      {
         perror("r1");
         exit(1);
      }
      
      sz = write(fd, "hello geeks\n", strlen("hello geeks\n"));
      
      printf("called write(% d, \"hello geeks\\n\", %d)."
        " It returned %d\n", fd, strlen("hello geeks\n"), sz);
      
      close(fd);
    }
    

    输出:

    called write(3, "hello geeks\n", 12).  it returned 11
    

    在这里,运行代码后在文件foo.txt中看到时,您会看到“ hello geeks ”。如果foo.txt文件中已经包含一些内容,则写入系统调用将覆盖该内容,并且所有先前的内容都将被删除,并且文件中仅包含“ hello geeks ”内容。

从程序中打印“ hello world”,而无需使用任何printf或cout函数。

// C program to illustrate
// I/O system Calls
#include
#include
#include
#include
  
int main (void)
{
    int fd[2];
    char buf1[12] = "hello world";
    char buf2[12];
  
    // assume foobar.txt is already created
    fd[0] = open("foobar.txt", O_RDWR);        
    fd[1] = open("foobar.txt", O_RDWR);
      
    write(fd[0], buf1, strlen(buf1));         
    write(1, buf2, read(fd[1], buf2, 12));
  
    close(fd[0]);
    close(fd[1]);
  
    return 0;
}

输出:

hello world

在此代码中,首先将buf1数组的字符串“ hello world”写入stdin fd [0],然后将该字符串写入stdin到buf2数组。之后,将buf2数组写入stdout并打印输出“ hello world ”。

想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。