嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十二)文件IO

简介: 嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十二)文件IO

4.文件IO


这部分内容只是简单的讲解一下关于文件I/O的知识。这部分内容如果要深入去了解,还要去看《操作系统》这本书。参考书:


1670752894877.jpg

这2本书的内容类似,第一本对知识点有更细致的描述,适合初学者;第二本比较直接,一上来就是各种函数的介绍,适合当作字典,不懂时就去翻看一下。

做纯Linux应用的入门,看这2本书就可以了,不需要学习我们的视频。我们的侧重于“嵌入式Linux”。


在Linux系统中,一切都是“文件”:普通文件、驱动程序、网络通信等等。所有的操作,都是通过“文件IO”来操作的。所以,很有必要掌握文件操作的常用接口。


4.1 文件从哪来?

1670752908774.jpg


4.2 怎么访问文件?


4.2.1 通用的IO模型:open/read/write/lseek/close


使用GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart

04_嵌入式Linux应用开发基础知识\source\06_fileio\copy.c


copy.c源码如下:

01
02 #include <sys/types.h>
03 #include <sys/stat.h>
04 #include <fcntl.h>
05 #include <unistd.h>
06 #include <stdio.h>
07
08 /*
09  * ./copy 1.txt 2.txt
10  * argc    = 3
11  * argv[0] = "./copy"
12  * argv[1] = "1.txt"
13  * argv[2] = "2.txt"
14  */
15 int main(int argc, char **argv)
16 {
17      int fd_old, fd_new;
18      char buf[1024];
19      int len;
20
21      /* 1. 判断参数 */
22      if (argc != 3)
23      {
24              printf("Usage: %s <old-file> <new-file>\n", argv[0]);
25              return -1;
26      }
27
28      /* 2. 打开老文件 */
29      fd_old = open(argv[1], O_RDONLY);
30      if (fd_old == -1)
31      {
32              printf("can not open file %s\n", argv[1]);
33              return -1;
34      }
35
36      /* 3. 创建新文件 */
37      fd_new = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
38      if (fd_new == -1)
39      {
40              printf("can not creat file %s\n", argv[2]);
41              return -1;
42      }
43
44      /* 4. 循环: 读老文件-写新文件 */
45      while ((len = read(fd_old, buf, 1024)) > 0)
46      {
47              if (write(fd_new, buf, len) != len)
48              {
49                      printf("can not write %s\n", argv[2]);
50                      return -1;
51              }
52      }
53
54      /* 5. 关闭文件 */
55      close(fd_old);
56      close(fd_new);
57
58      return 0;
59 }
60


本节源码完全可以在Ubuntu上测试,跟在ARM板上没什么不同。

执行以下命令编译、运行:

$ gcc -o copy copy.c
$ ./copy  copy.c new.c


4.2.2 不是通用的函数:ioctl/mmap


使用GIT下载所有源码后,本节源码位于如下目录:

01_all_series_quickstart

04_嵌入式Linux应用开发基础知识\source\06_fileio\copy_mmap.c


在Linux中,还可以把一个文件的所有内容映射到内存,然后直接读写内存即可读写文件。


copy_mmap.c源码如下:

01
02 #include <sys/types.h>
03 #include <sys/stat.h>
04 #include <fcntl.h>
05 #include <unistd.h>
06 #include <stdio.h>
07 #include <sys/mman.h>
08
09 /*
10  * ./copy 1.txt 2.txt
11  * argc    = 3
12  * argv[0] = "./copy"
13  * argv[1] = "1.txt"
14  * argv[2] = "2.txt"
15  */
16 int main(int argc, char **argv)
17 {
18      int fd_old, fd_new;
19      struct stat stat;
20      char *buf;
21
22      /* 1. 判断参数 */
23      if (argc != 3)
24      {
25              printf("Usage: %s <old-file> <new-file>\n", argv[0]);
26              return -1;
27      }
28
29      /* 2. 打开老文件 */
30      fd_old = open(argv[1], O_RDONLY);
31      if (fd_old == -1)
32      {
33              printf("can not open file %s\n", argv[1]);
34              return -1;
35      }
36
37      /* 3. 确定老文件的大小 */
38      if (fstat(fd_old, &stat) == -1)
39      {
40              printf("can not get stat of file %s\n", argv[1]);
41              return -1;
42      }
43
44      /* 4. 映射老文件 */
45      buf = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd_old, 0);
46      if (buf == MAP_FAILED)
47      {
48              printf("can not mmap file %s\n", argv[1]);
49              return -1;
50      }
51
52      /* 5. 创建新文件 */
53      fd_new = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
54      if (fd_new == -1)
55      {
56              printf("can not creat file %s\n", argv[2]);
57              return -1;
58      }
59
60      /* 6. 写新文件 */
61      if (write(fd_new, buf, stat.st_size) != stat.st_size)
62      {
63              printf("can not write %s\n", argv[2]);
64              return -1;
65      }
66
67      /* 5. 关闭文件 */
68      close(fd_old);
69      close(fd_new);
70
71      return 0;
72 }
73


本节源码完全可以在Ubuntu上测试,跟在ARM板上没什么不同。

执行以下命令编译、运行:

$ gcc -o copy_mmap copy_mmap.c
$ ./copy_mmap  copy_mmap.c  new2.c


4.3 怎么知道这些函数的用法?


Linux下有3大帮助方法:help、man、info。

想查看某个命令的用法时,比如查看ls命令的用法,可以执行:

ls  --help


help只能用于查看某个命令的用法,而man手册既可以查看命令的用法,还可以查看函数的详细介绍等等。它含有9大分类,如下:

1   Executable programs or shell commands       // 命令
2   System calls (functions provided by the kernel)  // 系统调用,比如 man 2 open
3   Library calls (functions within program libraries)  // 函数库调用
4   Special files (usually found in /dev)             // 特殊文件, 比如 man 4 tty 
5   File formats and conventions eg /etc/passwd  // 文件格式和约定, 比如man 5 passwd
6   Games  // 游戏
7   Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) //杂项
8   System administration commands (usually only for root) // 系统管理命令
9   Kernel routines [Non standard]  // 内核例程


比如想查看open函数的用法时,可以直接执行“man open”,发现这不是想要内容时再执行“man 2 open”。

在man命令中可以及时按“h”查看帮助信息了解快捷键。常用的快捷键是:


f  往前翻一页

b  往后翻一页

/patten 往前搜

?patten 往后搜


就内容来说,info手册比man手册编写得要更全面,但man手册使用起来更容易些。

以书来形容info手册和man手册的话,info手册相当于一章,里面含有若干节,阅读时你需要掌握如果从这一节跳到下一节;而man手册只相当于一节,阅读起来当然更容易。

就个人而言,我很少使用info命令。

可以直接执行“info”命令后,输入“H”查看它的快捷键,在info手册中,某一节被称为“node”,常用的快捷键如下:

Up          Move up one line.
Down        Move down one line.
PgUp        Scroll backward one screenful.
PgDn        Scroll forward one screenful.
Home        Go to the beginning of this node.
End         Go to the end of this node.
TAB         Skip to the next hypertext link.
RET         Follow the hypertext link under the cursor.
l           Go back to the last node seen in this window.
[           Go to the previous node in the document.
]           Go to the next node in the document.
p           Go to the previous node on this level.
n           Go to the next node on this level.
u           Go up one level.
t           Go to the top node of this document.
d           Go to the main 'directory' node.


4.4 系统调用函数怎么进入内核?


1670753030823.jpg


4.5 内核的sys_open、sys_read会做什么?

1670753039340.jpg

相关文章
|
3天前
|
Android开发
鸿蒙开发:自定义一个简单的标题栏
本身就是一个很简单的标题栏组件,没有什么过多的技术含量,有一点需要注意,当使用沉浸式的时候,注意标题栏的位置,需要避让状态栏。
鸿蒙开发:自定义一个简单的标题栏
|
3天前
|
API
鸿蒙开发:切换至基于rcp的网络请求
本文的内容主要是把之前基于http封装的库,修改为当前的Remote Communication Kit(远场通信服务),无非就是通信的方式变了,其他都大差不差。
鸿蒙开发:切换至基于rcp的网络请求
|
7天前
|
Linux 开发工具 Perl
在Linux中,有一个文件,如何删除包含“www“字样的字符?
在Linux中,如果你想删除一个文件中包含特定字样(如“www”)的所有字符或行,你可以使用多种文本处理工具来实现。以下是一些常见的方法:
31 5
|
7天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
23 6
|
7天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
32 6
|
8天前
|
监控 Linux Perl
Linux 命令小技巧:显示文件指定行的内容
在 Linux 系统中,处理文本文件是一项常见任务。本文介绍了如何使用 head、tail、sed 和 awk 等命令快速显示文件中的指定行内容,帮助你高效处理文本文件。通过实际应用场景和案例分析,展示了这些命令在代码审查、日志分析和文本处理中的具体用途。同时,还提供了注意事项和技巧,帮助你更好地掌握这些命令。
21 4
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
4月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
2月前
|
Java 大数据 API
Java 流(Stream)、文件(File)和IO的区别
Java中的流(Stream)、文件(File)和输入/输出(I/O)是处理数据的关键概念。`File`类用于基本文件操作,如创建、删除和检查文件;流则提供了数据读写的抽象机制,适用于文件、内存和网络等多种数据源;I/O涵盖更广泛的输入输出操作,包括文件I/O、网络通信等,并支持异常处理和缓冲等功能。实际开发中,这三者常结合使用,以实现高效的数据处理。例如,`File`用于管理文件路径,`Stream`用于读写数据,I/O则处理复杂的输入输出需求。
|
3月前
|
Java 数据处理
Java IO 接口(Input)究竟隐藏着怎样的神秘用法?快来一探究竟,解锁高效编程新境界!
【8月更文挑战第22天】Java的输入输出(IO)操作至关重要,它支持从多种来源读取数据,如文件、网络等。常用输入流包括`FileInputStream`,适用于按字节读取文件;结合`BufferedInputStream`可提升读取效率。此外,通过`Socket`和相关输入流,还能实现网络数据读取。合理选用这些流能有效支持程序的数据处理需求。
46 2