linux读写api

  • read write

    #include <unistd.h>
    ssize_t read(int fd, void *buf, size_t nbytes);
                    Returns: number of bytes read, 0 if end of file, −1 on error
    ssize_t write(int fd, const void *buf, size_t nbytes);
                    Returns: number of bytes written if OK, −1 on error
    

    nbytes 参数指定最多能读取的字节数。(size_t数据类型属于无符号整数类型。) buffer 参数提供用来存放输入数据的内存缓冲区地址。缓冲区至少应有nbytes个字节。
    读写操作都是从当前偏移量开始, 在成功返回之前, 该偏移量将增加实际读到/写入的字节数.

  • pread pwrite

    #include <unistd.h>
    ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
                Returns: number of bytes read, 0 if end of file, −1 on error
    ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
                Returns: number of bytes written if OK, −1 on error
    

    pread函数相当于先后调用了lseek和read函数,但是还是有区别的,有以下两点区别:1. pread函数是原子操作,而先后调用两个函数不是原子操作;2. pread函数是不会改变当前文件偏移量的,而read和write函数会改变当前文件偏移量。
    pread, pwrite - read from or write to a file descriptor at a given offset.
    pread() reads up to count bytes from file descriptor fd at offset offset (from the start of the file) into the buffer starting at buf. The file offset is not changed.
    pwrite() writes up to count bytes from the buffer starting at buf to the file descriptor fd at offset offset. The file offset is not changed.
    从指定偏移处进行读写, 且读写完成后文件的偏移量不变.

    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <string.h>
    
    int main(int argc,char *argv[])
    {
        int fd = open("pread.txt",O_RDWR|O_CREAT,0777);
        int num = write(fd,"Hello World!\n",strlen("Hello World!\n"));
        if (num < 0)
        {
            perror("write error!\n");
            return -1;
        }
        int offset = lseek(fd,0,SEEK_CUR);
        printf("num = %d,offset = %d\n",num,offset); // num = 13,offset = 13;
    
        pwrite(fd,"My Best Friends!",strlen("My Best Friends!"),6);
    
        char buf[20] = "",buf1[20] = "";
        int ret = read(fd,buf,sizeof(buf));
        if (ret < 0)
        {
            perror("read error!\n");
            return -1;
        }
    
        int offset1 = lseek(fd,0,SEEK_CUR);
        printf("ret = %d,offset1 = %d\n",ret,offset1); // ret = 9,offset1 = 22;
    
        pread(fd,buf1,sizeof(buf1),6);
        printf("buf = %s,buf1 = %s\n",buf,buf1);// buf =  Friends!,buf1 = My Best Friends!
    
        return 0;
    }
    
  • readv 和 writev
    readv 和 writev 函数用于在一次函数调用中读写多个连续的缓冲区. 有时也将这两个函数称为散布读(scatter read)和聚集写(gather write).

    #include <sys/uio.h>
    ssize_t readv(int fd, const struct iovec *iov, int iovcnt);
    ssize_t writev(int fd, const struct iovec *iov, int iovcnt);
                Both return: number of bytes read or written, −1 on error
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <stdlib.h>
    #include<stdio.h>
    #include<sys/uio.h>
    
    #define BUF_SIZE 100
    
    int main(int argc, char *argv[])
    {
            int str_len;
            struct iovec vec[2];
            char buf1[BUF_SIZE]={0};
            char buf2[BUF_SIZE]={0};
    
            int fd = open(argv[1], O_RDONLY);
    
            //vec[0].iov_base=buf1;
            vec[0].iov_base=calloc(1, BUF_SIZE);
            vec[0].iov_len=2;
            //vec[1].iov_base=buf2;
            vec[1].iov_base=calloc(1, BUF_SIZE);
            vec[1].iov_len=BUF_SIZE;
    
            str_len=readv(fd,vec,2);
            puts((char *)(vec[0].iov_base));
            puts((char *)(vec[1].iov_base));
            return 0;
    }
    
    #if 0
    #include <sys/uio.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <string.h>
    
    int main(int argc,char *argv[])
    {
            ssize_t size;
            char buf1[9] = "abc";
            char buf2[9] = "sss";
            struct iovec iov[2];
    
            int fd1=open(argv[1], O_WRONLY);
    
            iov[0].iov_base=buf1;
            iov[0].iov_len=strlen(buf1);
            iov[1].iov_base=buf2;
            iov[1].iov_len=strlen(buf2);
    
            size=writev(fd1,iov,2);
    
            close(fd1);
            return 0;
    }
    #endif
    
  • readn writen
    不是标准函数.
    通常, 在读写一个管道, 网络设备或者终端时,
    一次read操作的返回数据可能少于要求的数据, 即使还没达到文件的尾端可可能是这样.
    一次write操作的返回值也可能少于指定输出的字节数. 这可能是由某个原因造成的, 例如, 内核输出缓冲区变满.
    readn好writen的动能分别是读, 写定值的N字节数据, 并处理返回值可能小于要求值的情况. 这两个函数只是按需多次调用read和write直至读, 写了N个字节.

    #include "apue.h"
    ssize_t readn(int fd, void *buf, size_t nbytes);
    ssize_t writen(int fd, void *buf, size_t nbytes);
                Both return: number of bytes read or written, −1 on error
    
  • fread fwrite 二进制I/O

    #include <stdio.h>
    size_t fread(void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
    size_t fwrite(const void *restrict ptr, size_t size, size_t nobj, FILE *restrict fp);
                Both return: number of objects read or written
    

    getc, fgetc, getchar, fgets, fputs等标准IO库函数是以一次一个字符或者一次一行进行操作的. 如果进行二进制操作, 那我们更愿意一次读或写一个完整的结构体. 如果用getc或putc读写一个结构, 那么必须循环通过整个结构, 每次循环一个字节, 一次读或写一个字节, 这会非常麻烦而且费时. 如果使用fputs和fgets, 那么因为fputs在遇到null字节时就停止, 而在结构体中可能含有null字节, 所以不能使用它实现读结构体的要求. 相似的, 如果输入数据中包含null字节或换行符, 则fgets也不能正常工作. 而fread和fwrite就出现了.
    这些函数有以下常见的用法:

    • 读或写一个二进制数组. 例如, 为了将一个浮点数组的第2~5个元素写至一文件上, 可以编写如下程序:
      float data[10];
      if (fwrite(&data[2], sizeof(float), 4, fp) != 4)
          err_sys("fwrite error");
      
      其中, 指定size为每个数组元素的长度, nobj为欲写的元素个数.
    • 读或者写一个结构体.
      struct {
          short count;
          long total;
          char name[NAMESIZE];
      } item;
      
      if (fwrite(&item, sizeof(item), 1, fp) != 1)
          err_sys("fwrite error");
      
      其中, 指定size为结构的长度, nobj为1(要写对象的个数).
      fread和fwrite返回读或者写的对象个数. 对于读, 如果出错或达到文件尾端, 则此数字可以少于nobj. 在这种情况下, 应调用ferror或feof以判断究竟是哪一种情况. 对于写, 如果返回值少于要求的nobj, 则出错.
      使用二进制I/O的问题是, 在两个异构系统上读写数据, 对同样的结构体二进制的存储方式不同而导致不能正确的fread和fwrite.
  • 套接字数据传输
    套接字端点为一个文件描述符, 只要建立连接, 就可以使用read和write来通过套接字通信. 在套接字描述符上使用read和write是非常有意义的, 因为这意味着可以将套接字描述符传递给那些原先为处理本地文件而设计的函数.

    • recv()和 send()
      此系统调用可在已连接的套接字上执行 I/O 操作。它们提供了专属于套接字的功能,而这些功能在传统的 read()和 write()系统调用中是没有的。

      #include <sys/socket.h>
      ssize_t send(int sockfd, const void *buf, size_t nbytes, int flags);
                  Returns: number of bytes sent if OK, −1 on error 
      
      ssize_t recv(int sockfd, void *buf, size_t nbytes, int flags);
                  Returns: length of message in bytes,
                  0 if no messages are available and peer has done an orderly shutdown, or −1 on error
      

      当send成功返回时, 数据已经被无错误地发到网络驱动程序上了, 并不保证连接的另一端的进程就一定接受到了数据.
      对于支持报文边界的协议, 如果尝试发送的单个报文的长度超过协议所支持的最大长度, 那么send会失败. 对于字节流协议, send会阻塞直到整个数据传输完成.
      如果发送者已经调用shutdown来结束传输, 或者网络协议支持按默认的顺序关闭并且发送端已经关闭, 那么当所有的数据接收完毕后, recv会返回0.

    • recvfrom sendto
      sendto和send类似, 区别在于sendto可以在无连接的套接字上指定一个目标地址. 对于面向字节的套接字, 目标地址是被忽略的, 因为连接中隐含了目标地址. 对于无连接的套接字, 除非先调用connect设置了目标地址, 佛则不能使用send. sendto提供了发送报文的另一种方式.
      recvfrom可以用来得到数据发送者的源地址, 常用于无连接的套接字. 否则, recvfrom等同于recv.

      #include <sys/socket.h>
      ssize_t sendto(int sockfd, const void *buf, size_t nbytes, int flags, const struct sockaddr *destaddr, socklen_t destlen);
                  Returns: number of bytes sent if OK, −1 on error
      
      ssize_t recvfrom(int sockfd, void *restrict buf, size_t len, int flags, struct sockaddr *restrict addr, socklen_t *restrict addrlen);
                  Returns: length of message in bytes,
                      0 if no messages are available and peer has done an orderly shutdown, or −1 on error
      
    • recvmsg sendmsg
      通过套接字发送数据时, 还有另一个选择, 可以调用带有msghdr结构的sendmsg来指定多重缓冲区传输数据, 这和writev函数很相似. 也常用来传递文件描述符.

      #include <sys/socket.h>
      ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
                  Returns: number of bytes sent if OK, −1 on error
      
      ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
                  Returns: length of message in bytes,
                      0 if no messages are available and peer has done an orderly shutdown, or −1 on error
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值