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

2021年3月22日15:24:40 发表评论 606 次浏览

重要术语

什么是文件描述符

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

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

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

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

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

/ dev / tty

:终端的内存中替代

终奌站

:组合键盘/视频屏幕

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

从标准输入读取=>从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系统调用:

创造:

用于创建一个新的空文件。

Syntax in C language: 
int creat(char *filename, mode_t mode)

参数

filename:你要创建的文件的名称

mode:表示新文件的权限。

返回值:

返回第一个未使用的文件描述符(通常在进程中首次创建时使用3, 因为保留了0、1、2 fd)

错误时返回-1

在OS中如何运作

在磁盘上创建新的空文件

创建文件表条目

设置第一个未使用的文件描述符以指向文件表条目

使用的返回文件描述符, 失败时为-1

打开

:用于打开文件以进行读取, 写入或两者同时进行。

Syntax in C language 
#include<sys/types.h>
#include<sys/stat.h>
#include <fcntl.h>  
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<stdio.h>
#include<fcntl.h>
#include<errno.h>
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

关:

告诉操作系统你已经完成了文件描述符, 然后关闭fd指向的文件。

Syntax in C language
#include <fcntl.h>
int close(int fd);

参数

fd:文件描述符

返回

成功时为0。

-1表示错误。

它在操作系统中的工作方式

销毁文件描述符表的元素fd引用的文件表条目

–只要没有其他过程指向它!

将文件描述符表的元素fd设置为NULL

// C program to illustrate close system Call
#include<stdio.h>
#include <fcntl.h>
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<stdio.h>
#include<fcntl.h>
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因为当创建主进程时, 然后fd0、1、2已经被标准输入, 标准输出和斯特德。所以第一个未使用的文件描述符是3在文件描述符表中。之后在close()系统调用中释放了它3文件描述符, 然后设置3文件描述符为null。因此, 当我们调用第二个open()时, 第一个未使用的fd也是3。因此, 该程序的输出为3.

读:

从文件描述符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<stdio.h>
#include <fcntl.h>
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<stdio.h> 
#include<unistd.h> 
#include<fcntl.h>
#include<stdlib.h>
  
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

描述符fd1和fd2每个描述符都有自己的打开文件表条目, 因此每个描述符都有自己的文件位置foob​​ar.txt。因此, 从fd2读取的第一个字节foob​​ar.txt, 输出为c = f, 不是c = o.

写:

将buf中的cnt字节写入与fd相关的文件或套接字。 cnt不应大于INT_MAX(在limits.h头文件中定义)。如果cnt为零, 则write()仅返回0, 而不会尝试任何其他操作。

#include <fcntl.h>
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<stdio.h>
#include <fcntl.h>
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中看到"你好极客"。如果foo.txt文件中已经包含一些内容, 则写入系统调用将覆盖该内容, 并且所有先前的内容已删除而且只有"你好极客内容将存在于文件中。

从程序中打印" hello world", 而不使用任何printf或cout函数。

// C program to illustrate
// I/O system Calls
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<fcntl.h>
  
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数组的字符串"你好, 世界"首先将其写入stdin fd [0], 然后将该字符串写入stdin到buf2数组。之后, 将buf2阵列写入stdout并打印输出"你好, 世界"。

如果发现任何不正确的地方, 或者想分享有关上述主题的更多信息, 请写评论。

木子山

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: