精华内容
下载资源
问答
  • 学习记录:unix环境高级编程之 read 与write 函数详解 备注:本博文非本人所写,本人觉得此文讲的非常地道通俗易懂,所以摘录在此以方便以后再次查看 read函数从打开的设备或文件中读取数据。 ...
    学习记录:unix环境高级编程之 read 与write  函数详解
    备注:本博文非本人所写,本人觉得此文讲的非常地道通俗易懂,所以摘录在此以方便以后再次查看


    read 函数从打开的设备或文件中读取数据。
    #include <unistd.h>  ssize_t read(int fd, void *buf, size_t count); 返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0
    参数 count 是请求读取的字节数,读上来的数据保存在缓冲区 buf 中,同时文件的当前读写位置向后移。注意这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写位置是记在内核中的,而使用C标准I/O库时的读写位置是用户空间I/O缓冲区中的位置

    fread就是通过read来实现的,fread是C语言的库,而read是系统调用
    但是差别在read每次读的数据是调用者要求的大小,比如调用要求读取10个字节数据,read就会读10个字节数据到数组中,而fread不一样,为了加快读的速度,fread每次都会读比要求更多的数据,然后放到缓冲区中,这样下次再读数据只需要到缓冲区中去取就可以了。

    fread每次会读取一个缓冲区大小的数据,32位下一般是4096个字节,相当于调用了read(fd,buf,4096)

    比如需要读取512个字节数据,分4次读取,调用read就是:
    for(i=0; i<4; ++i)
    read(fd,buf,128)
    一共有4次系统调用

    而fread一次就读取了4096字节放到缓冲区了,所以省事了


    比如用 fgetc 读一个字节, fgetc 有可能从内核中预读1024个字节到I/O缓冲区中,再返回第一个字节,这时该文件在内核中记录的读写位置是1024,而在 FILE 结构体中记录的读写位置是1。注意返回值类型是 ssize_t ,表示有符号的 size_t ,这样既可以返回正的字节数、0(表示到达文件末尾)也可以返回负值-1(表示出错)。 read 函数返回时,返回值说明了 buf 中前多少个字节是刚读上来的。有些情况下,实际读到的字节数(返回值)会小于请求读的字节数 count ,例如:
    • 读常规文件时,在读到count个字节之前已到达文件末尾。例如,距文件末尾还有30个字节而请求读100个字节,则read返回30,下次read将返回0。

    • 从终端设备读,通常以行为单位,读到换行符就返回了。

    • 从网络读,根据不同的传输层协议和内核缓存机制,返回值可能小于请求的字节数,后面socket编程部分会详细讲解。

    write 函数向打开的设备或文件中写数据。
    #include <unistd.h>  ssize_t write(int fd, const void *buf, size_t count); 返回值:成功返回写入的字节数,出错返回-1并设置errno
    写常规文件时, write 的返回值通常等于请求写的字节数 count ,而向终端设备或网络写则不一定。

    读常规文件是不会阻塞的,不管读多少字节,read一定会在有限的时间内返回。从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用read读终端设备就会阻塞,如果网络上没有接收到数据包,调用read从网络读就会阻塞,至于会阻塞多长时间也是不确定的,如果一直没有数据到达就一直阻塞在那里。同样,写常规文件是不会阻塞的,而向终端设备或网络写则不一定。



    现在明确一下阻塞(Block) 这个概念。当进程调用一个阻塞的系统函数时,该进程被置于睡眠(Sleep) 状态,这时内核调度其它进程运行,直到该进程等待的事件发生了(比如网络上接收到数据包,或者调用 sleep 指定的睡眠时间到了)它才有可能继续运行。与睡眠状态相对的是运行(Running) 状态,在Linux内核中,处于运行状态的进程分为两种情况:
    • 正在被调度执行。CPU处于该进程的上下文环境中,程序计数器(eip)里保存着该进程的指令地址,通用寄存器里保存着该进程运算过程的中间结果,正在执行该进程的指令,正在读写该进程的地址空间。

    • 就绪状态。该进程不需要等待什么事件发生,随时都可以执行,但CPU暂时还在执行另一个进程,所以该进程在一个就绪队列中等待被内核调度。系统中可能同时有多个就绪的进程,那么该调度谁执行呢?内核的调度算法是基于优先级和时间片的,而且会根据每个进程的运行情况动态调整它的优先级和时间片,让每个进程都能比较公平地得到机会执行,同时要兼顾用户体验,不能让和用户交互的进程响应太慢。


    下面这个小程序从终端读数据再写回终端。
    例 28.2. 阻塞读终端

    #include <unistd.h>
    #include <stdlib.h>

    int main(void)
    {
    char buf[10];
    int n;
    n = read(STDIN_FILENO, buf, 10);
    if (n < 0) {
    perror("read STDIN_FILENO");
    exit(1);
    }
    write(STDOUT_FILENO, buf, n);
    return 0;
    }


    执行结果如下:
    $ ./a.out  hello(回车) hello $ ./a.out  hello world(回车) hello worl$ d bash: d: command not found

    第一次执行a.out的结果很正常,而第二次执行的过程有点特殊,现在分析一下:

    1. Shell进程创建a.out进程,a.out进程开始执行,而Shell进程睡眠等待a.out进程退出。

    2. a.out调用read时睡眠等待,直到终端设备输入了换行符才从read返回,read只读走10个字符,剩下的字符仍然保存在内核的终端设备输入缓冲区中。

    3. a.out进程打印并退出,这时Shell进程恢复运行,Shell继续从终端读取用户输入的命令,于是读走了终端设备输入缓冲区中剩下的字符d和换行符,把它当成一条命令解释执行,结果发现执行不了,没有d这个命令。


    如果在open一个设备时指定了O_NONBLOCK标志,read/write就不会阻塞。以read为例,如果设备暂时没有数据可读就返回-1,同时置errnoEWOULDBLOCK(或者EAGAIN ,这两个宏定义的值相同),表示本来应该阻塞在这里(would block,虚拟语气),事实上并没有阻塞而是直接返回错误,调用者应该试着再读一次(again)。这种行为方式称为轮询(Poll) ,调用者只是查询一下,而不是阻塞在这里死等,这样可以同时监视多个设备:
    while(1) {  非阻塞read(设备1);  if(设备1有数据到达)   处理数据;  非阻塞read(设备2);  if(设备2有数据到达)   处理数据;  ... }
    如果read(设备1)是阻塞的,那么只要设备1没有数据到达就会一直阻塞在设备1的read调用上,即使设备2有数据到达也不能处理,使用非阻塞I/O就可以避免设备2得不到及时处理。
    非阻塞I/O有一个缺点,如果所有设备都一直没有数据到达,调用者需要反复查询做无用功,如果阻塞在那里,操作系统可以调度别的进程执行,就不会做无用功了。在使用非阻塞I/O时,通常不会在一个 while 循环中一直不停地查询(这称为Tight Loop ),而是每延迟等待一会儿来查询一下,以免做太多无用功,在延迟等待的时候可以调度其它进程执行。
    while(1) {  非阻塞read(设备1);  if(设备1有数据到达)   处理数据;  非阻塞read(设备2);  if(设备2有数据到达)   处理数据;  ...  sleep(n); }
    这样做的问题是,设备1有数据到达时可能不能及时处理,最长需延迟n秒才能处理,而且反复查询还是做了很多无用功。以后要学习的 select(2) 函数可以阻塞地同时监视多个设备,还可以设定阻塞等待的超时时间,从而圆满地解决了这个问题。
    以下是一个非阻塞I/O的例子。目前我们学过的可能引起阻塞的设备只有终端,所以我们用终端来做这个实验。程序开始执行时在0、1、2文件描述符上自动打开的文件就是终端,但是没有 O_NONBLOCK 标志。所以就像 例 28.2 “阻塞读终端” 一样,读标准输入是阻塞的。我们可以重新打开一遍设备文件 /dev/tty (表示当前终端),在打开时指定 O_NONBLOCK 标志。
    O_NONBLOCK 以不可阻断的方式打开文件,也就是无论有无数据读取或等待,都会立即返回进程之中。
    例 28.3. 非阻塞读终端
    从终端设备或网络读则不一定,如果从终端输入的数据没有换行符,调用 read 读终端设备就会阻塞

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

    #define MSG_TRY "try again\n"

    int main(void)
    {
    char buf[10];
    int fd, n;
    fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
    if(fd<0) {
    perror("open /dev/tty");
    exit(1);
    }
    tryagain:
    n = read(fd, buf, 10);
    if (n < 0) {
    if (errno == EAGAIN) {
    sleep(1);
    write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
    goto tryagain;

    perror("read /dev/tty");
    exit(1);
    }
    write(STDOUT_FILENO, buf, n);
    close(fd);
    return 0;
    }

    直到按下回车把之前的输入输出(最多10个),然后停止。


    以下是用非阻塞I/O实现等待超时的例子。既保证了超时退出的逻辑又保证了有数据到达时处理延迟较小。

    例 28.4. 非阻塞读终端和等待超时

    read:既可以返回正的字节数、0(表示到达文件末尾)也可以返回负值-1(表示出错)

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

    #define MSG_TRY "try again\n"
    #define MSG_TIMEOUT "timeout\n"

    int main(void)
    {
    char buf[10];
    int fd, n, i;
    fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
    if(fd<0) {
    perror("open /dev/tty");
    exit(1);
    }
    for(i=0; i<5; i++) {
    n = read(fd, buf, 10);
    if(n>=0)
    break;
    if(errno!=EAGAIN) {
    perror("read /dev/tty");
    exit(1);
    }
    sleep(1);
    write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
    }
    if(i==5)
    write(STDOUT_FILENO, MSG_TIMEOUT, strlen(MSG_TIMEOUT));
    else
    write(STDOUT_FILENO, buf, n);
    close(fd);
    return 0;
    }
    展开全文
  • write函数详解与read函数的详解

    万次阅读 多人点赞 2018-03-20 00:39:46
    write() 头文件:#include&lt;unistd.h&gt; 原型: ssize_t write(int fd,const void*buf,size_t count); 参数说明: fd:是文件描述符(write所对应的是写,即就是1) buf:通常是一个字符串,需要...

    write()

    头文件:#include<unistd.h>
    

    原型:

    ssize_t write(int fd,const void*buf,size_t count);
    参数说明:
      fd:是文件描述符(write所对应的是写,即就是1)
      buf:通常是一个字符串,需要写入的字符串
      count:是每次写入的字节数
    

    返回值:

     成功:返回写入的字节数
     失败:返回-1并设置errno
      ps: 写常规文件时,write的返回值通常等于请求写的字节
           数count, 而向终端设备或者网络写时则不一定
    

    read()

    头文件:#include<unistd.h>
    功能:用于从文件描述符对应的文件读取数据(从打开的设备或文件中读取数据)
    
    

    原型:

    ssize_t read(int fd,void*buf,size_t count)
    参数说明:
    fd:      是文件描述符
    buf:     为读出数据的缓冲区;
    count:   为每次读取的字节数(是请求读取的字节数,读上来的数据保
             存在缓冲区buf中,同时文件的当前读写位置向后移)

    返回值:

     成功:返回读出的字节数
     失败:返回-1,并设置errno,如果在调用read
           之前到达文件末尾,则这次read返回0
    
    

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<unistd.h>
    int main()
    {
       const char*msg="hello\n";
       int len = strlen(msg);
       write(1,msg,len);//write所对应的文件描述符为1
       char buf[1024]={0};
       read(0,buf,len);//read所对应的文件描述符为0
       return 0;
    }

    运行结果:
    这里写图片描述

    fread函数read函数的区别

    1.fread函数是封装好的库函数,而read函数是系统函数,一般来说,fread效率更高;
    2.读取文件的差别:fread函数功能更强大,可以读取结构体的二进制文件,但是如果是最底层的操作,用到文件描述符的话,用read会更好。

    展开全文
  • read()函数: #include <unistd.h> int read(int filedes, void *buff, int nbytes) ;//(文件描述符, 将读取的数据放到该地址, 将要...write()函数: #include <unistd.h> int write(int fi...

    read()函数:

    #include <unistd.h>
    int read(int filedes, void *buff, int nbytes) ;//(文件描述符, 将读取的数据放到该地址, 将要读取的数据大小)
    返回:实际读到的字节数,若已到文件尾为0,若出错为- 1。读出来的数据不会再末尾加'\0',和fread()不同。
    

    write()函数:

    #include <unistd.h>
    int write(int filedes, const void * buff, int nbytes) ;//(文件描述符, 将写入的数据地址, 将要写入的数据大小)
    返回:若成功为已写的字节数,若出错为- 1
    

    #实例代码:将一个已经存在的文件拷贝到新建的文件中

    #include<sys/types.h>
    #include<sys/stat.h>
    #include<fcntl.h>
    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include <string.h>
    
    int main(){
    	int fd, fd1, count, ret;
    	char buf[512];
    	memset(buf, 0, sizeof(buf));//将数组清0
    
    	//只读方式打开文件
    	fd = open("example.text", O_RDONLY);
    	if(fd == -1){
    		perror("open file fail:\n");
    		exit(1);
    	}
    	printf("fd = %d\n", fd);
    
    	//创建一个新文件
    	fd1 = open("new_file.text", O_WRONLY | O_CREAT, 0777);
    	if(fd1 == -1){
    		perror("open file fail:\n");
    		exit(1);
    	}
    	printf("fd1 = %d\n", fd1);
    
    	//读取数据到buf数组中
    	count = read(fd, buf, sizeof(buf));//返回值>0是成功的字节数,=0是读完,-1是读取失败
    	if(count == -1){
    		perror("read fail:\n");
    		exit(1);
    	}
    	//循环复制数据到新建的文件中
    	while(count){
    		ret = write(fd1, buf, count); //返回值>0是写成功的字节数,失败返回-1
    		if(ret == -1){
    			perror("write");
    			exit(1);
    		}
    		printf("write bytes:%d\n", ret);
    		count = read(fd, buf, sizeof(buf));
    	}
    
    	//关闭文件
    	close(fd);
    	close(fd1);
    }
    
    展开全文
  • open函数详解与close函数详解

    万次阅读 多人点赞 2018-03-20 20:26:27
    open() 头文件:#include&lt;fcntl.h&gt;//在centos6.0中只要此头文件...功能:打开和创建文件(建立一个文件描述符,其他的函数可以通过文 件描述符对指定文件进行读取与写入的操作。) 原型 int o...

    open()

    头文件:#include<fcntl.h>//在centos6.0中只要此头文件就可以
           #include<sys/types.h>
           #incldue<sys/stat.h>
    功能:打开和创建文件(建立一个文件描述符,其他的函数可以通过文
         件描述符对指定文件进行读取与写入的操作。)

    原型

    int open(const char*pathname,int flags);
    int open(const char*pathname,int flags,mode_t mode);
    参数说明:
    1.pathname
      要打开或创建的目标文件
    2.flags
      打开文件时,可以传入多个参数选项,用下面的
      一个或者多个常量进行“或”运算,构成falgs
      参数:
      O_RDONLY:   只读打开
      O_WRONLY:   只写打开
      O_RDWR:     读,写打开
    这三个常量,必须制定一个且只能指定一个
      O_CREAT:    若文件不存在,则创建它,需要使
                  用mode选项。来指明新文件的访问权限
      O_APPEND:   追加写,如果文件已经有内容,这次打开文件所
                  写的数据附加到文件的末尾而不覆盖原来的内容
    
    

    ps:open函数具体使用那个,和具体应用场景相关,如目标文件存在,使用两个参数的open,如果目标文件不存在,需要open创建,则第三个参数表示创建文件的默认权限

    返回值

    成功:新打开的文件描述符
    失败:-1
    open返回的文件描述符一定是最小的而且没有被使用的

    fopen与open的区别

    以可写的方式fopen一个文件时,如果文件不存在则会自动创建,而open一个文件时必须明确O_CREAT才会创建文件,否则文件不存在就出错返回

    close

    头文件:#include<unistd.h>
    功能:关闭一个已经打开的文件

    原型

    int close(int fd)
    参数说明:
     fd:是需要关闭的文件描述符

    返回值

    成功:返回0;
    失败:返回-1,并设置errno

    打开的文件描述符一定要记得关闭,否则资源会被大量的占用,导致内存不够

    open打开的文件存在时:
    示例:
    1.
    代码:

    #include<stdio.h>
    #include<string.h>
    #include<fcntl.h>
    #include<unistd.h>
    #include<stdlib.h>
    int main()
    {
     int fd=open("myfile",O_WRONLY);
     if(fd<0)
     {
      perror("open");
      exit(1);
     }
     const char*msg="hello open\n";
     int count = 6;
     while(count--)
     {
      write(fd,msg,strlen(msg));
     }
     close(fd);
     return 0;
    }
    

    运行结果:
    这里写图片描述
    2.
    代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<fcntl.h>
    #include<unistd.h>
    int main()
    {
     int fd=open("myfile",O_RDWR);
     if(fd<0)
     {
      perror("open");
      exit(1);
     }
     const char*msg="hello  hahaha\n";
     int count= 10;
     while(count--)
     {
     write(fd,msg,strlen(msg));
     }
     char buf[1024]={0};
     int num=10;
     while(num--)
     {
     read(fd,buf,strlen(msg));
     }
     close(fd);
     return 0;
    }
    

    运行结果:
    这里写图片描述

    open打开的文件不存在时:

    1.
    代码:

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<string.h>
    #include<fcntl.h>
    int main()
    {
     int fd=open("file",O_WRONLY|O_CREAT,0644);
     //file文件不存在,所以在书写第二个参数时,记得把O_CREAT加上,
     //如果不加O_CREAT的话,程序就会报此文件不存在
     if(fd<0)
     {
      perror("open");
      exit(1);
     }
     const char*msg="hello file\n";
     int count=10;
     while(count--)
     {
      write(fd,msg,strlen(msg));
     }
     close(fd);
     return 0;
    }
    

    运行结果:
    这里写图片描述

    展开全文
  • ssize_t write(int fd, const void *buf, size_t count); //功能:write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。 //返回值:返回值write()会返回实际写入的字节数。当有错误发生时则返回-1,...
  • fatfs文件系统详解之f_write函数分析

    千次阅读 2020-05-31 18:36:43
    本篇分析f_write()函数,fatfs文件系统对应的不知道文件的读写,也对应了文件的其他的操作,也有文件夹的操作,函数分析确实是一个非常耗时耗精力的事情,此函数分析完之后,就结束函数分析。 分析假设 (1)假设一...
  • Python 内置函数详解

    万次阅读 多人点赞 2019-11-13 17:21:35
    不过,在大家公认的所谓内置函数里面,有很多并不是真的函数,而是内置类,只是因为使用起来和真正的函数没有什么不同,所以也就约定俗成地统称为内置函数了。比如,我们常说的类型转换函数 int()、str()、float() ...
  • CreateFile函数详解

    万次阅读 2019-04-16 10:04:07
    CreateFile函数详解 CreateFile函数创建或打开下列对象,并返回一个可以用来访问这些对象的句柄。 文件 pipes 邮槽 通信资源 磁盘驱动器(仅适用于windowsNT) 控制台 文件夹(仅用于打开) HANDLE CreateFile( ...
  • 在进行C语言学习的时候我们了解到了C语言相关的一些IO操作,如fopen,fwrite,fread,fprintf,fclose等相关函数,他们都是由C库函数提供的一些函数,是将操作系统的系统调用加以封装,虽说Linux是由C语言实现的,...
  • stat函数详解

    万次阅读 多人点赞 2018-09-20 16:24:44
    Linux系统函数之文件系统管理(二) stat函数 ​ 作用:获取文件信息 ​ 头文件:include &lt;sys/types.h&gt; #include &lt;sys/stat.h&gt; #include &lt;unistd.h&gt; ​ 函数...
  • pipe函数详解

    千次阅读 2013-10-23 21:28:28
    pipe函数详解 转载地址:http://blog.chinaunix.net/uid-24004458-id-335420.html 相关函数 mkfifo,popen,read,write,fork mkfifo函数的作用是在文件系统中创建一个文件,该文件用于提供FIFO功能,即命名...
  • select函数详解

    万次阅读 多人点赞 2019-01-23 10:43:15
    select函数详解背景说明定义介绍、参数说明原理返回值pselect总结案例案例1案例2 说明:本文整合网络资源和man帮助文档,请酌情参考。 背景 select函数是实现IO多路复用的一种方式。 什么是IO多路复用? 举一个简单...
  • send函数详解

    万次阅读 2019-01-23 10:41:14
    send函数详解sendsendtosendmsg 说明:本文主要是对man 帮助文档的翻译,若有错误,欢迎指正。 send send:是一个系统调用函数,用来发送消息到一个套接字中,和sendto,sendmsg功能相似。 概要: #include &lt...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 55,656
精华内容 22,262
关键字:

write函数详解