Linux系统应用编程---文件IO

简介: Linux系统应用编程---文件IO

文件描述符

files_struct *file结构体记录在task_struct结构体中,*file指向文件描述符。

一个进程默认打开三个文件描述符  

1.     STDIN_FILENO 0
2. 
3.     STDOUT_FILENO 1
4. 
5.     STDERR_FILENO 2

新打开文件返回文件描述符表中未使用的最小文件描述符

一、文件打开与关闭

open函数打开文件,open原型如下:

1. int open(const char * pathname, int flags);
2. 
3. int open(const char * pathname, int flags, mode_t mode);
  • 只有用到O_CREAT参数的时候,才会使用mode参数
  • 返回值:打开成功返回文件描述符,错误返回-1.
  • flags必选项:以下三个常数中必须指定一个,且仅允许指定一个。

* O_RDONLY 只读打开

* O_WRONLY 只写打开

* O_RDWR 可读可写打开

以下可选项可以同时指定0个或多个,和必选项按位或起来作为flags参数。可选项有很多,这里只介绍一部分,其它选项可参考open(2)的Man Page:

* O_APPEND 表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾

而不覆盖原来的内容。

* O_CREAT 若此文件不存在则创建它。使用此选项时需要提供第三个参数mode,表示该

文件的访问权限。

* O_EXCL 如果同时指定了O_CREAT,并且文件已存在,则出错返回。

* O_TRUNC 如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断(Truncate)为0字节。

* O_NONBLOCK 对于设备文件,以O_NONBLOCK方式打开可以做非阻塞I/O(Nonblock I/O)

 

关闭文件用close函数,close函数原型如下:

int close (int fd);

close返回值,关闭成功返回0,错误返回-1.

二、文件读写

read函数从打开的设备或文件中读取数据

ssize_t read(int fd, void *buf, size_t count)
  • 返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0.
  • fd是要读取的文件的文件描述符,参数count是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后移。

 

write函数向打开的设备或文件中写数据

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

返回值:成功返回写入的字节数,出错返回-1并设置errno

 

下面使用文件IO来实现一个cp命令类似的功能

1. #include <stdio.h>
2. #include <sys/types.h>
3. #include <sys/stat.h>
4. #include <fcntl.h>
5. #include <stdlib.h>
6. #include <unistd.h>
7. #include <string.h>
8. 
9. #define SIZE 8192
10. 
11. int main(int argc, char * argv[])
12. {
13.        char buf[SIZE];
14.        int fd_src, fd_dest, len;     
15. 
16. if(argc < 3){
17.               printf("./mycp src dest.\n");
18. exit(1);
19.        }
20. 
21. 
22. fd_src = open(argv[1], O_RDONLY);
23. fd_dest = open(argv[2], O_CREAT | O_WRONLY | O_TRUNC, 0777);
24. /*
25. *成功返回读到的字节数
26. *读到文件末尾返回0
27. *读失败返回-1
28. */
29.        while((len = read(fd_src, buf, sizeof(buf))) >0 )
30. write(fd_dest, buf, len);      
31. 
32. close(fd_src);
33. close(fd_dest);
34. 
35. return 0;
36. }

执行结果如下:

可以看到拷贝的2.txt与1..txt文件一样

三、文件定位

lseek可移动当前文件读写位置,函数原型:

off_t lseek (int fd, off_t offset, int whence)
  • lseek()函数的作用是,重置文件描述符fd关联打开的文件偏移量,把这个偏移量重置为参数offset,在重置时要根据指令whence来做,whence可包含的指令有三个

SEEK_SET       表从文件的起始位置偏移offset大小的字节

SEEK_CUR     表从当前位置加上offset大小的字节

SEEK_END     表从未见末尾加上offset大小的字节

  • 返回值:

lseek返回值:当lseek成功完成时,lseek()返回的偏移量是距离文件开头的偏移量,大小是以自己为单位衡量。如果错误返回值为-1,并设置errno的值

 

例1:用lseek拓展一个文件,注意一定要有一次写操作

1. #include <sys/types.h>
2. #include <sys/stat.h>
3. #include <fcntl.h>
4. #include <unistd.h>
5. #include <stdio.h>
6. #include <errno.h>
7. #include <stdlib.h>
8. 
9. int main(void)
10. {
11.        int fd = open("filetest", O_RDWR);
12. if(fd < 0){
13.               perror("open filetest");
14. exit(-1);
15.        }
16. 
17. //拓展一个文件,一定要有一次写操作
18.        lseek(fd, 0x1000, SEEK_SET);
19. //write(fd, "a", 1);
20. close(fd);
21. 
22. return 0;
23. }

注释后://write(fd, "a", 1);

去掉注释

 

例2:用lseek输出一个文件的大小

1. #include <sys/types.h>
2. #include <sys/stat.h>
3. #include <fcntl.h>
4. #include <unistd.h>
5. #include <stdio.h>
6. #include <errno.h>
7. #include <stdlib.h>
8. 
9. int main(void)
10. {
11.        int file_size;
12.        int fd = open("abc", O_RDWR);
13. if(fd < 0){
14.               perror("open abc");
15. exit(-1);
16.        }
17. 
18. fd = open("hello", O_RDWR);
19. if(fd < 0){
20.               perror("open hello");
21. exit(-1);
22.        }
23. 
24. file_size = lseek(fd, 0, SEEK_END);
25.        printf("hello size = %d.\n", file_size);
26. close (fd);
27. 
28. return 0;
29. }

执行结果

 

四、设置/获取文件控制属性

fcntl函数原型如下:

1. #include <unistd.h>
2. 
3. #include <fcntl.h>
4. 
5. int fcntl(int fd, int cmd);
6. 
7. int fcntl(int fd, int cmd, long arg);
8. 
9. int fcntl(int fd, int cmd, struct flock *lock);

先看一个例程,这里重新打开STDIN_FILENO,并添加非阻塞的属性,当用户有输入时,直接在标准输出上显示用户的输入,实现类似cat的功能(只不过这里是非阻塞)

1. #include <unistd.h>
2. #include <sys/types.h>
3. #include <sys/stat.h>
4. #include <string.h>
5. #include <stdlib.h>
6. #include <errno.h>
7. #include <string.h>
8. #include <fcntl.h>
9. #include <error.h>
10. #include <stdio.h>
11. 
12. #define MSG_TRY "try again\n"
13. 
14. int main(void)
15. {
16.        char buf[10];
17.        int fd, n;
18. fd = open("/dev/tty", O_RDONLY | O_NONBLOCK);
19. if(fd < 0){
20.               perror("open /dev/tty");
21. exit(1);
22.        }    
23. 
24. tryagain:
25.        n = read(fd, buf, 10);
26. if(n < 0){
27. if(errno == EAGAIN){
28.                      sleep(1);
29. write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
30.                      goto tryagain;
31.               }
32.               perror("read /dev/tty");
33. exit(1);
34.        }
35. write(STDOUT_FILENO, buf, n);
36. close(fd);
37. 
38. return 0;
39. }

 

为什么我们不直接对STDIN_FILENO做非阻塞read,而要重新open一遍/dev/tty呢?因为STDIN_FILENO在程序启动时已经被自动打开了,而我们需要在调用open时指定O_NONBLOCK标志。

这里用fcntl函数改变一个已打开的文件的属性,可以重新设置读、写、追加、非阻塞等标志(这些标志称为File Status Flag),而不必重新open文件。

所以上面的代码可修改如下,用fcntl函数实现

 

1. #include <unistd.h>
2. #include <fcntl.h>
3. #include <errno.h>
4. #include <string.h>
5. #include <stdlib.h>
6. 
7. #define MSG_TRY "try again\n"
8. 
9. int main(void)
10. {
11.     char buf[10];
12.     int n;
13.     int flags;
14. 
15.     flags = fcntl(STDIN_FILENO, F_GETFL);
16.     flags |= O_NONBLOCK;
17. 
18. if (fcntl(STDIN_FILENO, F_SETFL, flags) == -1) {
19.         perror("fcntl");
20. exit(1);
21.     }
22. 
23. tryagain:
24.     n = read(STDIN_FILENO, buf, 10);
25. if (n < 0) {    
26. if (errno == EAGAIN) {
27.         sleep(1);
28. write(STDOUT_FILENO, MSG_TRY, strlen(MSG_TRY));
29.         goto tryagain;
30.     }
31. 
32.     perror("read stdin");
33. exit(1);
34. }
35. 
36. write(STDOUT_FILENO, buf, n);
37. 
38. return 0;
39. }
相关文章
|
25天前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
39 5
|
26天前
|
Linux 开发工具 Perl
在Linux中,有一个文件,如何删除包含“www“字样的字符?
在Linux中,如果你想删除一个文件中包含特定字样(如“www”)的所有字符或行,你可以使用多种文本处理工具来实现。以下是一些常见的方法:
40 5
|
27天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
43 6
|
27天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
64 6
|
28天前
|
监控 Linux Perl
Linux 命令小技巧:显示文件指定行的内容
在 Linux 系统中,处理文本文件是一项常见任务。本文介绍了如何使用 head、tail、sed 和 awk 等命令快速显示文件中的指定行内容,帮助你高效处理文本文件。通过实际应用场景和案例分析,展示了这些命令在代码审查、日志分析和文本处理中的具体用途。同时,还提供了注意事项和技巧,帮助你更好地掌握这些命令。
41 4
|
1月前
|
网络协议 Linux
linux系统重要文件目录
本文介绍了Linux系统中的重要目录及其历史背景,包括根目录、/usr、/etc、/var/log和/proc等目录的结构和功能。其中,/etc目录下包含了许多关键配置文件,如网卡配置、DNS解析、主机名设置等。文章还详细解释了各目录和文件的作用,帮助读者更好地理解和管理Linux系统。
55 2
|
1月前
|
缓存 监控 Linux
|
1月前
|
Linux Shell 数据库
文件查找是Linux用户日常工作的重要技能介绍了几种不常见的文件查找方法
文件查找是Linux用户日常工作的重要技能。本文介绍了几种不常见的文件查找方法,包括使用`find`和`column`组合、`locate`和`mlocate`快速查找、编写Shell脚本、使用现代工具`fd`、结合`grep`搜索文件内容,以及图形界面工具如`Gnome Search Tool`和`Albert`。这些方法能显著提升文件查找的效率和准确性。
47 2
|
7月前
|
Linux
百度搜索:蓝易云【Linux中如何对文件进行压缩和解压缩?】
这些是在Linux中进行文件压缩和解压缩的常见方法。根据您的需求和具体情况,可能会使用其他压缩工具和选项。您可以通过查阅相应命令的帮助文档来获取更多详细信息。
90 1
|
7月前
|
NoSQL Java Linux
Linux常用命令(文件目录操作、拷贝移动、打包压缩、文本编辑、查找)
Linux常用命令(文件目录操作、拷贝移动、打包压缩、文本编辑、查找)