Linux操作系统是基于文件概念的。文件是以字符序列构成的信息载体。根据这一点,可以把I/O设备当做文件来处理,因此,在磁盘上的普通文件进行交互所用的统一系统调用可以直接用于I/O设备。这样大大简化了系统对于不同设备的处理,提高了效率。Linux中的文件主要分为6种:普通文件、目录文件、符号链接文件、管道文件、套接字文件和设备文件。

       那么,内核如何区分和引用特定的文件呢?这里用到了一个重要的概念——文件描述符。对于Linux而言,所有的设备和文件的操作都是通过文件描述符来进行的。文件描述符是一个非负的整数,它是一个索引值,并指向在内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;读写文件时,需要把文件描述符作为参数传递给相应的函数。

通常,一个进程启动时,都会打开3个流:标准输入、标准输出和标准错误。这3个流分别对应文件描述符0、1  和 2(对应的宏分别是STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO)。

基于文件描述符的I/O操作虽然不鞥直接移植到类Linux以外的系统上去(如Windows),但它往往是实现某些I/O操作的唯一途径,如Linux中底层文件操作函数、多路I/O、TCP/IP套接字编程接口等。同时,他们也很好地兼容POSIX标准,因此,可以很方便地移植到任何POSIX平台上。基于文件描述符的I/O操作是Linux中最常用的操作之一。

文件I/O相关函数:open() 、read() 、write() 、lseek() 和close() 。这些函数的特点是不带缓冲,直接对文件(包括设备)进行读写操作。这些函数不是ANSI C的组成部分,而是POSIX相关标准来定义。

1、文件打开与和关闭

 open()函数用于创建或打开文件,在打开或创建文件时可以指定文件打开方式及文件的访问权限。

函数原型如下:

[cpp] view plaincopy
  1. #include <sys/stat.h>
  2. #include <fcntl.h>
  3. int open(const char *pathname,int flags,int perms);

1)pathname: 被打开的文件名(可包括路径名)

2)flags(文件打开方式,这里介绍几个常用的)

O_RDONLY   只读

O_WRONLY  只写

O_RDWR       可读可写

这三者必有其一

O_CREAT    如果文件不存在,就创建一个新文件,并用第三个参数为其设置权限;

O_TRUNC    若文件已经存在,那么会删除文件中的全部原有数据,并且设置文件大小为0;

O_APPEND  以添加方式打开文件,在写文件时,文件读写文职自动指向文件的末尾,即将写入的数据添加到文件的末尾;

3)perms 新建文件的存取权限

      close()函数用于关闭一个被打开的文件。当一个进程终止时,所有打开的文件都有内核自动关闭。很多程序都利用这一特性而不显示地关闭一个文件。

函数原型:

[cpp] view plaincopy
  1. #include <unistd.h>
  2. int close(int fd);

2、文件读写

read()函数从文件中读取数据存放到缓冲区中,并返回实际读取的字节数。若返回0,则表示没有数据可读,即已达到文件尾。读操作从文件的当前读写位置开始读取数据,当前读写位置自动往后移动。

函数原型:

[cpp] view plaincopy
  1. #include <unistd.h>
  2. ssize_t read(int fd, void *buf,size_t count);

函数传入值:

fd  文件描述符;

buf 指定存储器读取数据的缓冲区;

count  指定读出的字节数;

函数返回值:

成功:读到的字节数;

0:已到达文件尾;

-1:出错;

在读到普通文件时,若读到要求的字节数之前已到达问价你的尾部,则返回的字节数会小于指定读出的字节数;

write()函数将数据写入文件中,并返回实际写入的字节数。写操作从文件的当前读写位置开始写入。对磁盘文件进行写操作时,若磁盘已满,write()函数返回失败;

函数原型:

[cpp] view plaincopy
  1. #include <unistd.h>
  2. ssize_t write(int fd,void  *buf ,size_t count);

函数传入值:

fd  文件描述符

buf  指定存储器写入数据的缓冲区

count  指定读出的字节数

函数返回值:

成功:已写的字节数

-1:出错

下面写个简单小程序,实现copy程序,完成文件的复制,代码如下:

[cpp] view plaincopy
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <sys/types.h>
  4. #include <fcntl.h>
  5. #include <sys/stat.h>
  6. #define maxsize 256
  7. int main(int argc, char *argv[])
  8. {
  9. int fd1,fd2;
  10. int byte;
  11. char buffer[maxsize];
  12. if(argc != 3)
  13. {
  14. printf("command error!\n");
  15. return -1;
  16. }
  17. if((fd1 = open(argv[1],O_RDONLY)) == -1)
  18. {
  19. perror("open fails");
  20. return -1;
  21. }
  22. if((fd2 = open(argv[2],O_WRONLY | O_CREAT | O_TRUNC ,0664)) == -1)//如果文件不存在,则创建,若存在,则覆盖;
  23. {
  24. perror("open fails");
  25. return -1;
  26. }
  27. while(1)
  28. {
  29. if((byte = read(fd1,buffer,maxsize)) > 0)
  30. write(fd2,buffer,byte);
  31. if(byte == 0)
  32. break; //如果读不到数据,则返回
  33. }
  34. close(fd1);
  35. close(fd2);
  36. return 0;
  37. }

执行结果如下:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/fileIO/open$ ls -l
  2. total 16
  3. -rwxrwxr-x 1 fs fs 7388 Jan  4 16:18 cp
  4. -rw-rw-r-- 1 fs fs  625 Jan  4 16:18 cp.c
  5. -rw-rw-r-- 1 fs fs  526 Jan  4 16:01 file1.c
  6. fs@ubuntu:~/qiang/fileIO/open$ ./cp file1.c file2.c
  7. fs@ubuntu:~/qiang/fileIO/open$ ls -l
  8. total 20
  9. -rwxrwxr-x 1 fs fs 7388 Jan  4 16:18 cp
  10. -rw-rw-r-- 1 fs fs  625 Jan  4 16:18 cp.c
  11. -rw-rw-r-- 1 fs fs  526 Jan  4 16:01 file1.c
  12. -rw-rw-r-- 1 fs fs  526 Jan  4 16:19 file2.c
  13. fs@ubuntu:~/qiang/fileIO/open$

我们可以看到,原来file2.c并不存在,执行完程序后,file2.c存在,且大小和file1.c相同;

3、文件定位

       lseek()函数对文件当前读写位置进行定位。它只能对可定位(可随机访问)文件操作。管道、套接字和大部分字符设备文件不支持此类操作;

函数原型:

[cpp] view plaincopy
  1. #include <unistd.h>
  2. #include <sys/types.h>
  3. off_t lseek(int fd ,off_t offset,int whence);

函数传入值:

fd  文件描述符

offset   相对于基准点whence 的偏移量。以字节为单位,正数表示向前移动,负数表示向后移动

whence 当前位置的基点

SEEK_SET:文件的起始位置

SEEK_CUR:文件当前读写位置

SEEK_END:文件的结束位置

函数的返回值:

成功:文件当前读写位置

-1:出错

我们可以通过lseek函数实现一个小功能:查看文件的大小,代码如下:

[cpp] view plaincopy
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <fcntl.h>
  4. #include <sys/stat.h>
  5. #include <sys/types.h>
  6. int main(int argc, const char *argv[])
  7. {
  8. int fd;
  9. int length;
  10. if(argc != 2)
  11. {
  12. printf("command error!\n");
  13. return -1;
  14. }
  15. if((fd = open(argv[1],O_RDONLY)) == -1)
  16. {
  17. perror("open fails");
  18. return -1;
  19. }
  20. length = lseek(fd,0,SEEK_END);
  21. printf("The length of %s is %d bytes!\n",argv[1],length);
  22. return 0;
  23. }

执行结果如下:

[cpp] view plaincopy
  1. fs@ubuntu:~/qiang/fileIO/lseek$ ls -l
  2. total 12
  3. -rwxrwxr-x 1 fs fs 7308 Jan  4 16:47 lseek
  4. -rw-rw-r-- 1 fs fs  424 Jan  4 16:46 lseek.c
  5. fs@ubuntu:~/qiang/fileIO/lseek$ ./lseek lseek.c
  6. The length of lseek.c is 424 bytes!
  7. fs@ubuntu:~/qiang/fileIO/lseek$

我们可以看到,得到了lseek.c正确大小!

Linux 系统应用编程——文件I/O相关推荐

  1. Linux系统及编程期末试题,《LINUX系统及其编程》考试试题及答案.doc

    <LINUX系统及其编程>考试试题及答案 <Linux系统及其编程>模拟练习参考答案 一.单项选择题 .Linux的根分区系统类型是 C . A. FAT16 B.FAT32 ...

  2. Linux C高级编程——文件操作之系统调用

    Linux C高级编程文件操作之系统调用 宗旨:技术的学习是有限的,分享的精神是无限的! 库函数是一些完成特定功能的函数,一般由某个标准组织制作发布,并形成一定的标准.使用库函数编写的函数一般可以应用 ...

  3. 理解Unix/Linux系统中的文件描述符

    简介 文件描述符是针对Unix/Linux的每个进程而言的,每个进程都维护了一个文件指针表,指针指向操作系统的文件.这里的文件是指的Unix/Linux系统所说的文件,Unix/Linux下一切皆文件 ...

  4. Linux学习-Linux系统及编程基础笔记

    useradd zhangsan passwd zhangsan visudo往/etc/sudoers文件中添加zhangsan #visudo 找到如下的行 root ALL=(ALL) ALL ...

  5. linux系统中的文件传输

    Linux系统中的文件传输 1 实验环境 2 scp命令 3 rsync命令 3.1 rsync和scp命令对比 3.2 rsync命令用法 4 文件的归档压缩 4.1 文件归档 4.2 文件压缩 4 ...

  6. Linux系统上的文件类型

    Linux系统上的文件类型 -: 常规文件 d: directory,目录文件 b: block device,块设备文件,支持以"block"为单位进行随机访问 c: chara ...

  7. Linux C高级编程——文件操作之库函数

    Linux C高级编程--文件操作之库函数 宗旨:技术的学习是有限的,分享的精神是无限的 --为什么要设计标准I/O库? 直接使用API进行文件访问时,需要考虑许多细节问题 例如:read.write ...

  8. linux物理内存地址与iomem,一种Linux系统物理内存镜像文件分析方法_4

    模块信息,如图7所示,给出了本发明的实施例中 模块结构关系图,modules变量指向某一个已加载模块结构体module地址,所有已加载模 块其module形成一个双向链表,如图7所示,据此可以获取到所 ...

  9. linux mount命令衔接,Linux mount命令详解:挂载Linux系统外的文件

    Linux mount命令详解:挂载Linux系统外的文件 <Linux挂载>一节讲到,所有的硬件设备必须挂载之后才能使用,只不过,有些硬件设备(比如硬盘分区)在每次系统启动时会自动挂载, ...

最新文章

  1. 网络对抗技术-实验报告一
  2. Codeforces Gym 100650B Countdown (离线)
  3. linux分配iomem,Linux中__iomem
  4. matplotlib绘图蓝本
  5. APPStore 审核收集
  6. php 抓取页面图片,php 抓取网页内容与图片的方法
  7. bootstrap内容部分API解读(1)
  8. 电脑格式化后需要重装系统吗_重装系统后c盘文件丢失,电脑重装系统后c盘文件能恢复吗...
  9. Eclipse 隐藏已关闭的项目
  10. moment转换时间戳_酷炫时间轮盘:JS元素圆形布局制作时间轮盘动画效果
  11. Cognos8.3 + oracle9i数据集市 建cube性能调整
  12. learning docker steps(3) ----- docker services 初次体验
  13. oracle数据库使用小结
  14. java工厂模式_java工厂模式
  15. 菜鸟记录:安卓手机导出微信聊天记录
  16. 蓝桥杯近三年初赛题之一(15年b组)
  17. 2019 高教社杯数模竞赛A题 高压油管的压力控制 题解
  18. 20130327-[转]讲完这个故事我就要嫁给别人
  19. VMware中的快照功能的原理与使用
  20. QGC地面站二次开发(一)地面站介绍以及软件框架(3)QGC汉化步骤介绍

热门文章

  1. WPF程序将DLL嵌入到EXE的两种方法
  2. PL/SQL块中不能直接执行DDL语句(错误)
  3. python中ix用法_Python中使用ix的数据帧子集
  4. 使用Hadoop所需要的一些Linux基础
  5. 什么叫静态构建版本号码_为什么要使用GatsbyJS构建静态网站
  6. 浅谈关于java中的深浅拷贝
  7. mysql-防止XSS攻击
  8. [模板]LIS(最长上升子序列)
  9. 使用HBuilder新建项目
  10. windows 64位 安装mvn提示 不是内部或外部命令