read/write/open

来源:互联网 发布:淘宝微信转换工具 编辑:程序博客网 时间:2024/06/06 05:22
// 文件名:mycp.c#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#define BUFFERSIZE 4096int main(int argc, char* argv[]) {  int srcfd = open(argv[1], O_RDONLY); // 用只读的方式打开一个已经存在的文件  int dstfd = open(argv[2], O_CREAT | O_WRONLY, 0666); // 创建一个新的文件,这个文件只能写,权限是 0666。有关 linux 文件权限位,请参考后面。  int len  = 0;  char buffer[BUFFERSIZE] = {0}; // 临时缓冲区。  while((len = read(srcfd, buffer, BUFFERSIZE)) > 0) { // 循环读取数据    write(dstfd, buffer, len); // 写入数据  }  close(srcfd); // 关闭文件  close(dstfd);  return 0;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 编译 
    编写完成后,使用正的命令编译后生成一个 mycp 的可执行文件。
$ gcc mycp.c -o mycp
  • 1
  • 1
  • 执行 
    使用下面的方法来执行 mycp。意思是复制文件 mycp.c 到新文件 test 中去。
./mycp mycp.c test
  • 1
  • 1

看完后,不要慌,待我解释,一下子学习 3 个函数,可能让你难以接受。

函数 open

函数 open 的原型如下。

int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode);
  • 1
  • 2
  • 1
  • 2

在前面的代码中,用到了两次 open 函数,而且函数的参数个数也不一样,其实它和 printf 一样,也是一个可变参数函数。

int srcfd = open(argv[1], O_RDONLY);
  • 1
  • 1

这行的意思是打开文件 mycp.c(这个值是通过 argv[1]传过来的),后面的 O_RDONLY 的意思是,打开这个文件后,你只能读取。返回值 srcfd 是一个整数,这个整数在本进程内唯一的标识了 mycp.c 这个文件。它有个专用的名字,叫文件描述符,有关这个概念以后会慢慢深入,这里你就认为它表示 mycp.c 这个文件。


int dstfd = open(argv[2], O_CREAT | O_WRONLY, 0666);
  • 1
  • 1

这一行的 open 传了 3 个参数,这个函数是创建一个文件 test(这个值是通过 argv[2]传过来的),第二个参数是 O_CREAT | O_WRONLY,表示创建一个文件 test, 这个文件是只写的。0666是8进制数 666,表示 test 文件的权限是 -rw-rw-rw-。返回值 dstfd 唯一了标识了 test 这个文件。


open 函数的用法

  1. flags 有三个必选项,分别是 O_RDONLY, O_WRONLY, O_RDWR. 这三个值是互斥的,只能选一个。(如果你看过APUE这本书,那上面提到的是5选一,但是这里我不想讲另外的两个)
  2. flags 有很多可选项,O_CREAT, O_APPEND, O_EXCL, O_TRUNC, O_NONBLOCK. 这几个值是可以多选的。当然不能和必选项发生冲突。
  3. 如果填写了 O_CREAT 这个可选项,那个 open 函数的第 3 个参数 mode 就必需写。O_EXCL只和O_CREAT配合使用。如果 O_EXCL开启了,而且要创建的文件如果已存在,函数返回 -1。
  4. O_APPEND表示已追加的方式打开文件。
  5. O_TRUNC表示打开文件后,将长度截断成0.
  6. O_NONBLOCK针对设备文件,比如屏幕,网络,表示以非阻塞的方式打开 IO. 这个概念现在不提。

除了以上的选项外,linux 还提供了其它的选项,这里就不说了,因为不太常用。上面的选项目前对我们来说,已经足够。随着学习的深入,遇到了再讨论也不迟。如果想了解更多选项,请向 man 寻求帮助。在终端中输入man 2 open,就可以看到 open的详细介绍。

man 2 open中的 2,表示在 man 手册中的第2章查看 open,第 2 章描述的全部是 linux 系统接口。而第 3 章描述的都是C语言库函数。

flag 选项示例

open('test', O_RDONLY);                     // 只读方式打开open('test', O_WRONLY | O_APPEND);          // 追加的方式打开open('test', O_RDWR);                       // 读写的方式打开open('test', O_WRONLY | O_CREAT, 0666);     // 创建文件,只写,权限是 0666open('test', O_WRONLY | O_TRUNC);           // 只写打开,同时把文件长度截断成 0.
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

函数 read

  • 函数原型
ssize_t read(int fd, void *buf, size_t count);
  • 1
  • 1

size_t你可以理解成 unsigned int,而 ssize_t 你可以理解成 int。

关是读上面的mycp代码你可能就会使用 read 函数了,它表示从文件 fd 中期望读取 count 字节的数据。

它的返回值表示实际读取到的字节数。如果返回值为 0,表示已经读取到了文件末尾,如果为 -1,表示读取出错。

题外话:如果你是从设备(比如标准输入或网络中)读取数据,read 默认情况下阻塞,它会一直等待有数据到来为止才返回。如果一直没有数据到来,那么本进程会被操作系统投入睡眠

函数 write

ssize_t write(int fd, const void *buf, size_t count);
  • 1
  • 1

write 函数也很容易理解,表示我期望写入 count 个字节的数据。返回值表示实际写入的数据。

对于普通文件来说,返回值必须和 count 相等,否则意味着出错。

对于设备来说,返回值可以小于 count 的值,比如向网络中写数据。

题外话:如果你是向设备(比如标准输入或网络中)写数据,write 默认情况下阻塞,除非缓冲区有空位。如果缓冲区一直是满的,那么本进程会被操作系统投入睡眠

完整代码

#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <stdio.h>#define BUFFERSIZE 4096int main(int argc, char* argv[]) {  if (argc != 3) {    printf("usage:\n mycp src dst\n");    return 1;  }  int srcfd = open(argv[1], O_RDONLY);  if (srcfd == -1) {    perror("open");    return 1;  }  int dstfd = open(argv[2], O_CREAT | O_WRONLY, 0666);  if (dstfd == -1) {    perror("open");    return 1;  }  int len  = 0;  char buffer[BUFFERSIZE] = {0};  while((len = read(srcfd, buffer, BUFFERSIZE)) > 0) {    if (write(dstfd, buffer, len) != len) {      perror("write error");      return 1;    }     }  if (len < 0) {    perror("read error");    return 1;  }  close(srcfd); // 关闭文件  close(dstfd);  return 0;}
原创粉丝点击