使用Linux的文件API,经常看见一个东西,叫做文件描述符.

什么是文件描述符?

(1)文件描述符其实实质是一个数字,这个数字在一个进程中表示一个特定的含义,当我们open打开一个文件时,操作系统在内存中构建了一些数据结构来表示这个动态文件,然后返回给应用程序一个数字作为文件描述符,这个数字就和我们内存中维护这个动态文件的这些数据结构挂钩绑定上了,以后我们应用程序如果要操作这一个动态文件,只需要用这个文件描述符进行区分。

(2)文件描述符就是用来区分一个程序打开的多个文件的。

(3)文件描述符的作用域就是当前进程,出了当前进程这个文件描述符就没有意义了

(4)文件描述符fd的合法范围是0或者一个正数,不可能是一个负数

(5)open返回的fd必须记录好,以后向这个文件的所有操作都要靠这个fd去对应这个文件,最后关闭文件时也需要fd去指定关闭这个文件。如果在我们关闭文件前fd丢了,那么这个文件就没法关闭了也没法读写了

1)打开与读取文件

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6.  
  7. int main(int argc, char const *argv[]) {
  8.  
  9. int fd = -; //文件描述符
  10.  
  11. //打开文件
  12. fd = open( "ghostwu.txt", O_RDWR );
  13.  
  14. if ( - == fd ) {
  15. printf("文件打开失败\n");
  16. }else {
  17. printf("文件打开成功,fd=%d\n", fd );
  18. }
  19.  
  20. //读取文件
  21. int count = ;
  22. char buf[];
  23. count = read( fd, buf, );
  24. if ( - == count ) {
  25. printf("文件读取失败\n");
  26. }else {
  27. printf("文件读取成功,实际读取的字节数目为:%d\n内容为%s\n", count, buf );
  28. }
  29.  
  30. //关闭文件
  31. close( fd );
  32.  
  33. return ;
  34. }

需要在当前目录下存在ghostwu.txt这个文件,否则打开的时候失败,这里涉及2个api

int open(const char *pathname, int flags);

open非常简单,第一个参数就是文件路径, 第二个是文件模式,在man手册中还提供了其他几种方式。

ssize_t read(int fd, void *buf, size_t count);

第一个参数为文件描述符,就是open返回的那个值

第二个参数buf用来存储从文件中读取的内容

第三个参数,表示希望从文件中读取的内容( 注:这个count数字可以随便给,最终以返回的实际数目(read的返回值)为准

2)打开与写入文件

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7.  
  8. int main(int argc, char const *argv[]) {
  9.  
  10. int fd = -; //文件描述符
  11.  
  12. //打开文件
  13. fd = open( "ghostwu.txt", O_RDWR );
  14.  
  15. if ( - == fd ) {
  16. printf("文件打开失败\n");
  17. }else {
  18. printf("文件打开成功,fd=%d\n", fd );
  19. }
  20.  
  21. //写文件
  22. char buf[] = "I love Linux, Linux is very very good!!!";
  23. int count = ;
  24. count = write( fd, buf, strlen( buf ) );
  25. if ( - == count ) {
  26. printf("文件写入失败\n");
  27. }else {
  28. printf("文件写入成功,实际写入的字节数目为:%d\n", count);
  29. }
  30.  
  31. //关闭文件
  32. close( fd );
  33.  
  34. return ;
  35. }

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

第一个参数为文件描述符,就是open返回的那个值

第二个参数buf用来存储写入的内容

第三个参数,表示希望写入的文件大小

3)open的一些flag参数

1,只读与只写权限

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6.  
  7. int main(int argc, char const *argv[]) {
  8.  
  9. int fd = -; //文件描述符
  10.  
  11. //打开文件, O_RDONLY:只读权限,打开之后的文件只能读取,不能写入
  12. //打开文件, O_WRONLY:只写权限,打开之后的文件只能写入,不能读取
  13. // fd = open( "ghostwu.txt", O_RDONLY );
  14. fd = open( "ghostwu.txt", O_WRONLY );
  15.  
  16. if ( - == fd ) {
  17. printf("文件打开失败\n");
  18. }else {
  19. printf("文件打开成功,fd=%d\n", fd );
  20. }
  21.  
  22. //读取文件
  23. int count = ;
  24. char buf[];
  25. count = read( fd, buf, );
  26. if ( - == count ) {
  27. printf("文件读取失败\n");
  28. }else {
  29. printf("文件读取成功,实际读取的字节数目为:%d\n内容为%s\n", count, buf );
  30. }
  31.  
  32. //关闭文件
  33. close( fd );
  34.  
  35. return ;
  36. }

2,清空与追加

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7.  
  8. int main(int argc, char const *argv[]) {
  9.  
  10. int fd = -; //文件描述符
  11.  
  12. //打开文件
  13. //在O_RDWR模式下,对于一个已经存在的文件,且有内容,那么写入文件会覆盖对应大小的源文件内容【不是完全覆盖】
  14. // fd = open( "ghostwu.txt", O_RDWR );
  15. //在具有写入权限的文件中,使用O_TRUNC 会先把原来的内容清除,再写入新的内容
  16. // fd = open( "ghostwu.txt", O_RDWR | O_TRUNC );
  17. //在具有写入权限的文件中,使用O_APPEND 会把新内容追加到原来内容的后面
  18. // fd = open( "ghostwu.txt", O_RDWR | O_APPEND );
  19.  
  20. //在具有写入权限的文件中,使用O_APPEND和O_TRUNC O_TRUNC起作用,会把原来的内容清除,再写入新的内容
  21. fd = open( "ghostwu.txt", O_RDWR | O_APPEND | O_TRUNC );
  22.  
  23. if ( - == fd ) {
  24. printf("文件打开失败\n");
  25. return -;
  26. }else {
  27. printf("文件打开成功,fd=%d\n", fd );
  28. }
  29.  
  30. //写文件
  31. char buf[] = "new content";
  32. int count = ;
  33. count = write( fd, buf, strlen( buf ) );
  34. if ( - == count ) {
  35. printf("文件写入失败\n");
  36. return -;
  37. }else {
  38. printf("文件写入成功,实际写入的字节数目为:%d\n", count);
  39. }
  40.  
  41. //关闭文件
  42. close( fd );
  43.  
  44. return ;
  45. }

3,文件存在已否,创建文件与设置权限

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7.  
  8. int main(int argc, char const *argv[]) {
  9.  
  10. int fd = -;
  11.  
  12. // fd = open( "ghostwu.txt", O_RDWR | O_CREAT | O_EXCL );
  13.  
  14. /*
  15. 文件不存在:
  16. 创建这个文件 并打开成功
  17. 文件存在:
  18. 再次运行时(文件已经创建成功,存在了), 这时打开失败
  19. */
  20. // fd = open( "ghostwu.txt", O_RDWR | O_CREAT );
  21.  
  22. fd = open( "ghostwu.txt", O_RDWR | O_CREAT | O_EXCL, );
  23.  
  24. if( - == fd ) {
  25. printf("文件打开失败,错误号:%d\n", errno );
  26. perror( "open" );
  27. return -;
  28. }else {
  29. printf("文件打开成功\n");
  30. }
  31.  
  32. close( fd );
  33.  
  34. return ;
  35. }

上面用到了一个函数perror,errno和perror:

1)errno就是error number,意思就是错误号码。linux系统中对各种常见错误做了个编号,当函数执行错误时,函数会返回一个特定的errno编号来告诉我们这个函数到底哪里错了

2)errno是由操作系统来维护的一个全局变量,操作系统内部函数都可以通过设置errno来告诉上层调用者究竟刚才发生了一个什么错误

3)errno本身实质是一个int类型的数字,每个数字编号对应一种错误。当我们只看errno时只能得到一个错误编号数字,并不知道具体错在哪里,所以:linux系统提供了一个函数perror(意思print error),perror函数内部会读取errno并且将这个不好认的数字直接给转成对应的错误信息字符串,然后打印出来

4,lseek用来移动文件内部指针

简单应用:统计文件大小

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <errno.h>
  7.  
  8. int main(int argc, char const *argv[]) {
  9.  
  10. if ( argc != ) {
  11. printf("usage:%s %s\n", argv[], "filename");
  12. return -;
  13. }
  14.  
  15. int fd = -;
  16.  
  17. fd = open( argv[], O_RDWR );
  18.  
  19. if( - == fd ) {
  20. printf("文件打开失败,错误号:%d\n", errno );
  21. perror( "open" );
  22. return -;
  23. }else {
  24. printf("文件打开成功\n");
  25. }
  26.  
  27. //把指针移动到文件末尾,就是文件的大小
  28. int count = lseek( fd, , SEEK_END );
  29.  
  30. printf("文件大小为%d\n", count);
  31.  
  32. close( fd );
  33. return ;
  34. }

------------------------------------------分割线------------------------------------------

一、同一个进程,多次打开同一个文件,然后读出内容的结果是: 分别读【我们使用open两次打开同一个文件时,fd1和fd2所对应的文件指针是不同的2个独立的指针】

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <errno.h>
  6. #include <unistd.h>
  7.  
  8. int main(int argc, char const *argv[]) {
  9.  
  10. int fd1 = -;
  11. int fd2 = -;
  12. char buf1[] = {};
  13. char buf2[] = {};
  14. int count1 = ;
  15. int count2 = ;
  16.  
  17. fd1 = open( "ghostwu.txt", O_RDWR );
  18.  
  19. if ( - == fd1 ) {
  20. printf("文件打开失败\n");
  21. perror( "open" );
  22. return -;
  23. }else {
  24. printf("文件打开成功,fd1=%d\n", fd1);
  25. }
  26.  
  27. count1 = read( fd1, buf1, );
  28. if ( - == count1 ) {
  29. printf( "文件读取失败\n" );
  30. perror( "read" );
  31. }else {
  32. printf( "文件读取成功,读取的内容是%s\n", buf1 );
  33. }
  34.  
  35. fd2 = open( "ghostwu.txt", O_RDWR );
  36.  
  37. if ( - == fd1 ) {
  38. printf("文件打开失败\n");
  39. perror( "open" );
  40. return -;
  41. }else {
  42. printf("文件打开成功,fd2=%d\n", fd1);
  43. }
  44.  
  45. count2 = read( fd2, buf2, );
  46. if ( - == count2 ) {
  47. printf( "文件读取失败\n" );
  48. perror( "read" );
  49. }else {
  50. printf( "文件读取成功,读取的内容是%s\n", buf2 );
  51. }
  52.  
  53. close( fd1 );
  54. close( fd2 );
  55.  
  56. return ;
  57. }

二、同一个进程,多次打开同一个文件,然后写入内容的结果是: 分别写,当使用O_APPEND,就是接着写

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <errno.h>
  6. #include <unistd.h>
  7. #include <string.h>
  8.  
  9. int main(int argc, char const *argv[]) {
  10.  
  11. int fd1 = -;
  12. int fd2 = -;
  13. char buf1[] = "ghost";
  14. char buf2[] = "wu";
  15. int count1 = ;
  16. int count2 = ;
  17.  
  18. fd1 = open( "ghostwu.txt", O_RDWR );
  19.  
  20. if ( - == fd1 ) {
  21. printf("文件打开失败\n");
  22. perror( "open" );
  23. return -;
  24. }else {
  25. printf("文件打开成功,fd1=%d\n", fd1);
  26. }
  27.  
  28. count1 = write( fd1, buf1, strlen( buf1 ) );
  29. if ( - == count1 ) {
  30. printf( "文件写入失败\n" );
  31. perror( "write" );
  32. }else {
  33. printf( "文件写入成功,写入的内容是%s\n", buf1 );
  34. }
  35.  
  36. fd2 = open( "ghostwu.txt", O_RDWR );
  37.  
  38. if ( - == fd1 ) {
  39. printf("文件打开失败\n");
  40. perror( "open" );
  41. return -;
  42. }else {
  43. printf("文件打开成功,fd2=%d\n", fd1);
  44. }
  45.  
  46. count2 = write( fd2, buf2, strlen( buf2 ) );
  47. if ( - == count2 ) {
  48. printf( "文件写入失败\n" );
  49. perror( "write" );
  50. }else {
  51. printf( "文件写入成功,写入的内容是%s\n", buf2 );
  52. }
  53.  
  54. close( fd1 );
  55. close( fd2 );
  56.  
  57. return ;
  58. }

上面代码保持不变,再写入的时候加入flag标志:

fd1 = open( "ghostwu.txt", O_RDWR | O_APPEND );

fd2 = open( "ghostwu.txt", O_RDWR | O_APPEND );

三、 dup后的fd和原来打开文件的fd指向的是同一个文件,同时对这个文件写入时,是接着写

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7.  
  8. int main(int argc, char const *argv[]) {
  9.  
  10. int fd1 = -;
  11. int fd2 = -;
  12.  
  13. fd1 = open( "ghostwu.txt", O_RDWR );
  14.  
  15. if ( - == fd1 ) {
  16. perror( "open" );
  17. return -;
  18. }else {
  19. printf("文件打开成功:fd=%d\n", fd1);
  20. }
  21.  
  22. //dup后的文件,同时write 是接着写入
  23. fd2 = dup( fd1 );
  24. printf("文件dup成功:fd=%d\n", fd2);
  25.  
  26. //分别向fd1和fd2指向的文件写入
  27.  
  28. char buf1[] = "ghost";
  29. char buf2[] = "wu";
  30.  
  31. int count1 = -, count2 = -;
  32.  
  33. while ( ) {
  34. count1 = write( fd1, buf1, strlen( buf1 ) );
  35. if ( - == count1 ) {
  36. perror( "buf1->write" );
  37. return -;
  38. }else {
  39. printf("buf1->文件写入成功\n");
  40. }
  41.  
  42. sleep( );
  43.  
  44. count2 = write( fd2, buf2, strlen( buf2 ) );
  45. if ( - == count2 ) {
  46. perror( "buf2->write" );
  47. return -;
  48. }else {
  49. printf("buf2->文件写入成功\n");
  50. }
  51. }
  52.  
  53. close( fd1 );
  54. close( fd2 );
  55. return ;
  56. }

在linux系统中,内核占用了0、1、2这三个fd,当我们运行一个程序得到一个进程时,内部就默认已经打开了3个文件,

对应的fd就是0、1、2。分别叫stdin、stdout、stderr。也就是标准输入、标准输出、标准错误。接下来,我们把标准输出关闭,printf就不会输出,如果用dup复制原来的fd,那么新dup出来的fd就是1(对应标准输出)

之后标准输出的内容都会被写入到原来fd对应的那个文件

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <fcntl.h>
  5. #include <unistd.h>
  6. #include <string.h>
  7.  
  8. int main(int argc, char const *argv[]) {
  9.  
  10. int fd = -;
  11.  
  12. fd = open( "ghostwu2.txt", O_RDWR );
  13. if ( - == fd ) {
  14. perror( "open" );
  15. return -;
  16. }else {
  17. printf( "文件打开成功fd=%d\n", fd );
  18. }
  19.  
  20. //fd=0 对应stdin fd=1 对应 stdout fd=2 对应stderror
  21. close( ); //关闭fd=1的标准输出之后,printf输出看不见
  22.  
  23. int newFd = -;
  24.  
  25. newFd = dup( fd ); //newFd一定是1, 因为分配后的fd从最小的没被占用的开始
  26. char buf[];
  27. sprintf( buf, "%d", newFd ); //newFd转字符串型
  28. printf( "这是一段输出,由于newFd和fd关联到标准输出(newFd=1),会被写入到文件\n" );
  29. write( fd, buf, );
  30.  
  31. return ;
  32. }

Linux系统编程:简单文件IO操作的更多相关文章

  1. 【Linux 应用编程】文件IO操作 - 常用函数

    Linux 系统中的各种输入输出,设计为"一切皆文件".各种各样的IO统一用文件形式访问. 文件类型及基本操作 Linux 系统的大部分系统资源都以文件形式提供给用户读写.这些文件 ...

  2. linux系统编程之文件IO

    1.打开文件的函数open,第一个参数表示文件路径名,第二个为打开标记,第三个为文件权限 代码: #include <sys/types.h> #include <sys/stat. ...

  3. Linux系统编程001--系统IO

    1. 文件系统:用来存储.组织.管理文件的一套方式.协议 2. 文件 文件的属性:i-node唯一表示一个文件的存在与否 文件的内容 3. Linux系统如何实现文件的操作? 点击查看代码 硬件层: ...

  4. linux系统编程之文件与io(五)

    上一节中已经学习了文件描述符的复制,复制方法有三种,其中最后一种fcntl还并未使用到,关于这个函数,不光只有复制文件描述符的功能,还有其它一些用法,本节就对其进行一一剖析: fcntl常用操作: 这 ...

  5. linux系统编程之文件与io(一)

    经过了漫长的学习,C语言相关的的基础知识算是告一段落了,这也是尝试用写博客的形式来学习c语言,回过头来看,虽说可能写的内容有些比较简单,但是个人感觉是有史起来学习最踏实的一次,因为里面的每个实验都是自 ...

  6. UNIX系统编程:文件IO(I)

    1.标准C库中访问文件用的是文件指针FILE *(stdin,stdout,stderr):对于linux系统编程而言,所有对设备或文件的操作都是通过文件描述符进行的 2.当打开或者创建一个文件的时候 ...

  7. linux系统编程之文件与IO(一):文件描述符、open,close

    什么是IO? 输入/输出是主存和外部设备之间拷贝数据的过程 设备->内存(输入操作) 内存->设备(输出操作) 高级I/O ANSI C提供的标准I/O库称为高级I/O,通常也称为带缓冲的 ...

  8. Linux系统编程:文件I/O编程

    文件I/O操作在Linux编程时是经常会使用到的一个内容,通常可以把比较大的数据写到一个文件中来进行存储或者与其他进程进行数据传输,这样比写到一个全局数组或指针参数来实现还要方便好多. 一.文件常用操 ...

  9. linux c编程:文件的操作

    在Linux系统中,系统是通过inode来获得这个文件的信息.在Linux系统中,inode的信息都是封装在stat这个结构体中.可以通过man 2 stat来查看stat的具体结构.从中可以看到包含 ...

随机推荐

  1. C++中指向类的指针

    事情缘起是因为上班途中刷到了有个微博,那人说答对这个问题的请发简历. 看了就是关于指向C++类的指针的知识,原代码类似下面这样: class NullPointCall { public: void ...

  2. JSONArray - JSONObject - 遍历 \ 判断object空否

    public static void main(String[] args) { String str = "[{name:'a',value:'aa'},{name:'b',value:' ...

  3. C#将dataGridView中显示的数据导出到Excel(大数据量超有用版)

    开发中非常多情况下须要将dataGridView控件中显示的数据结果以Excel或者Word的形式导出来,本例就来实现这个功能. 因为从数据库中查找出某些数据列可能不是必需显示出来,在dataGrid ...

  4. [Sqoop]利用sqoop对mysql运行DML操作

    业务背景 利用sqoop对mysql进行查询.加入.删除等操作. 业务实现 select操作: sqoop eval \ --connect jdbc:mysql://127.0.0.1:3306/m ...

  5. Win32界面 主函数分析

    WinMain即(函数运行入口): p { margin-bottom: 0.25cm; line-height: 120% } int WINAPI WinMain (HINSTANCE hinst ...

  6. 摧枯拉朽,说说ES6的三把火

    阅读目录 我是 Jser 我骄傲 作用域 模块系统 类(Class) 我是 Jser 我骄傲 JavaScript 如今可谓是屌丝逆袭高富帅的代名词哈,从当初闹着玩似的诞生到现在 Github 上力压 ...

  7. tools: idea 2017 激活

    1.下载并安装ideaIU (https://www.jetbrains.com/idea/download/#section=windows ,下载Ultimate版)2.下载 JetbrainsC ...

  8. MyBatis 批量操作、集合遍历-foreach

    在使用mybatis操作数据库时,经常会使用到批量插入.IN条件查询的情况,这时就难免要使用到foreach元素.下面一段话摘自mybatis官网: foreach 元素的功能是非常强大的,它允许你指 ...

  9. 判断json数据是否包含key

    1.("key" in jsonObj) 如果有返回true 没有返回false 2.jsonObj.hasOwnProperty("key") 如果有返回tr ...

  10. iOS开发添加pch文件

    首先说一下pch的作用: 1.存放一些全局的宏(整个项目中都用得上的宏) 2.用来包含一些全部的头文件(整个项目中都用得上的头文件) 3.能自动打开或者关闭日志输出功能 如何在Xcode中添加pch文 ...