Linux应用开发基础知识——文件IO操作(三)

简介: Linux应用开发基础知识——文件IO操作(三)

       这 2 本书的内容类似,第一本对知识点有更细致的描述,适合初学者;第二 本比较直接,一上来就是各种函数的介绍,适合当作字典,不懂时就去翻看一下。 做纯 Linux 应用的入门,看这 2 本书就可以了,我们的侧重于“嵌入式 Linux”

一、文件IO

1.什么是文件:

       Linux 的文件既可以是真实保存到存储介质的文件也可以 是自身内核提供的虚拟文件,还可以是设备节点。

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

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 手册只相当于一节, 阅读起来当然更容易。

3.文件IO的分类

标准IO:   fopen/fread/fwrite/fseek/fflush/fclose

系统IO: open/read /write/lseek/close

 

这2种IO函数的区别:

二、使用open函数打开文件

1.用man命令进行查看文件使用方法

man 2 open

函数作用:

作用:打开或者创建一个文件

pathname: 文件路径名,或者文件名

flags:表示打开文件所采用的操作

O_RDONLY:只读模式

O_WRONLY:只写模式

O_RDWR:可读可写

O_APPEND:表示追加,如果原来文件里面有内容,则这次写入会写在文件的最末尾。

O_REAT:表示如果指定文件不存在,则创建这个文件

O_EXCL:表示如果要创建的文件已存在,则出错,同时返回--1,并且修改·errno·的值。

O_TRUNC:表示截断,如果文件存在,并且以只写、读写方式打开,则将其长度截断为0。“

2.open.c 源码如下:

 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
/*
*./open_ 1.txt
*argc    = 2
*argv[0] = "./open"
*argv[1] = "1.txt"
*/
int main(int argc, char **argv)
{
    int fd;
        if(argc != 2)
        {
                printf("Uage:%s <file>\n",argv[0]);
        return -1;
        }
 
    fd = open(argv[1],O_RDWR);
    if (fd < 0)
    {
        printf("can not open file %s\n",argv[1]);
        printf("errno = %d\n",errno);
        printf("err: %s\n",strerror(errno));
        perror("open");
    }
    else
    {
        printf("fd = %d\n",fd);
    }
    while(1)
    {
         sleep(10);
    }
 
    close(fd);
    return 0;
}

三、使用open函数创建文件

设置创建文件并开启权限

fd = open(argv[1],O_RDWR | O_CREAT | O_TRUNC,0644);

create.c 源码如下:

 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
/*
*./create   1.txt
*argc    = 2
*argv[0] = "./create"
*argv[1] = "1.txt"
*/
int main(int argc, char **argv)
{
    int fd;
        if(argc != 2)
        {
                printf("Uage:%s <file>\n",argv[0]);
        return -1;
        }
 
    fd = open(argv[1],O_RDWR | O_CREAT | O_TRUNC,0644);
    if (fd < 0)
    {
        printf("can not open file %s\n",argv[1]);
        printf("errno = %d\n",errno);
        printf("err: %s\n",strerror(errno));
        perror("open");
    }
    else
    {
        printf("fd = %d\n",fd);
    }
    while(1)
    {
         sleep(10);
    }
 
    close(fd);
    return 0;
}
 

四、使用write函数写文件

1.用man命令进行查看文件使用方法

2 .write.c 源码如下:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
/*
*./write   1.txt  str1 str2
*argc    >= 3
*argv[0] = "./write"
*argv[1] = "1.txt"
*/
int main(int argc, char **argv)
{
    int fd;
    int i;
    int len;
    if(argc < 3)
    {
        printf("Uage:%s <file> <string1> <string2> ...\n",argv[0]);
        return -1;
    }
 
    fd = open(argv[1],O_RDWR | O_CREAT | O_TRUNC,0644);
    if (fd < 0)
    {
        printf("can not open file %s\n",argv[1]);
        printf("errno = %d\n",errno);
        printf("err: %s\n",strerror(errno));
        perror("open");
    }
    else
    {
        printf("fd = %d\n",fd);
    }
 
    for(i = 2; i < argc; i ++)
    {
       len =  write(fd,argv[i],strlen(argv[i]));
       if(len != strlen(argv[i]))
       {
           perror("write");
           break;
       }
       write(fd,"\r\n",2);
    }
 
    close(fd);
    return 0;
}
 

五、lseek中间插入

1.用man命令进行查看文件使用方法

2 .write_in_poc.c 源码如下:

 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
/*
*./write   1.txt  str1 str2
*argc    >= 3
*argv[0] = "./write"
*argv[1] = "1.txt"
*/
int main(int argc, char **argv)
{
    int fd;
    int i;
    int len;
    if(argc != 2)
    {
        printf("Uage:%s <file>\n",argv[0]);
        return -1;
    }
 
    fd = open(argv[1],O_RDWR | O_CREAT,0644);
    if (fd < 0)
    {
        printf("can not open file %s\n",argv[1]);
        printf("errno = %d\n",errno);
        printf("err: %s\n",strerror(errno));
        perror("open");
    }
    else
    {
        printf("fd = %d\n",fd);
    }
 
    printf("lseek to offset 3 from file head\n");
    lseek(fd,3,SEEK_SET);
 
    write(fd,"123",3);
 
    close(fd);
    return 0;
}

六、读写文件

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

copy.c 源码如下:

 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
 
/*
 * ./copy 1.txt 2.txt
 * argc    = 3
 * argv[0] = "./copy"
 * argv[1] = "1.txt"
 * argv[2] = "2.txt"
 */
int main(int argc, char **argv)
{
        int fd_old, fd_new;
        char buf[1024];
        int len;
 
        /* 1. 判断参数 */
        if (argc != 3)
        {
                printf("Usage: %s <old-file> <new-file>\n", argv[0]);
                return -1;
        }
 
        /* 2. 打开老文件 */
        fd_old = open(argv[1], O_RDONLY);
        if (fd_old == -1)
        {
                printf("can not open file %s\n", argv[1]);
                return -1;
        }
 
        /* 3. 创建新文件 */
        fd_new = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
        if (fd_new == -1)
        {
                printf("can not creat file %s\n", argv[2]);
                return -1;
        }
 
        /* 4. 循环: 读老文件-写新文件 */
        while ((len = read(fd_old, buf, 1024)) > 0)
        {
                if (write(fd_new, buf, len) != len)
                {
                        printf("can not write %s\n", argv[2]);
                        return -1;
                }
        }
 
        /* 5. 关闭文件 */
        close(fd_old);
        close(fd_new);
 
        return 0;
}
 
1. book@100ask:~/source/06_fileio$ gcc -o copy copy.c
2. book@100ask:~/source/06_fileio$ ./copy copy.c new.c

2.不是通用的函数:ioctl/mmap

copy_mmap.c 源码如下:

 
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
 
/*
 * ./copy 1.txt 2.txt
 * argc    = 3
 * argv[0] = "./copy"
 * argv[1] = "1.txt"
 * argv[2] = "2.txt"
 */
int main(int argc, char **argv)
{
        int fd_old, fd_new;
        struct stat stat;
        char *buf;
 
        /* 1. 判断参数 */
        if (argc != 3)
        {
                printf("Usage: %s <old-file> <new-file>\n", argv[0]);
                return -1;
        }
 
        /* 2. 打开老文件 */
        fd_old = open(argv[1], O_RDONLY);
        if (fd_old == -1)
        {
                printf("can not open file %s\n", argv[1]);
                return -1;
        }
 
        /* 3. 确定老文件的大小 */
        if (fstat(fd_old, &stat) == -1)
        {
                printf("can not get stat of file %s\n", argv[1]);
                return -1;
        }
 
        /* 4. 映射老文件 */
        buf = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd_old, 0);
        if (buf == MAP_FAILED)
        {
                printf("can not mmap file %s\n", argv[1]);
                return -1;
        }
 
        /* 5. 创建新文件 */
        fd_new = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
        if (fd_new == -1)
        {
                printf("can not creat file %s\n", argv[2]);
                return -1;
        }
 
        /* 6. 写新文件 */
        if (write(fd_new, buf, stat.st_size) != stat.st_size)
        {
                printf("can not write %s\n", argv[2]);
                return -1;
        }
 
        /* 5. 关闭文件 */
        close(fd_old);
        close(fd_new);
 
        return 0;
}
1. book@100ask:~/source/06_fileio$ gcc -o copy_mmap copy_mmap.c
2. book@100ask:~/source/06_fileio$ ./copy_mmap copy_mmap.c new2.c

七、内核接口

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

       以 open/read 为例,从用户态调用 API 触发异常进入内核的过程,最后调用的 sys_call_table 的函数指针数组如下:

2.内核的 sys_open、sys_read 会做什么?

       进入内核后,sys_read/open 会首先根据参数判断文 件的类型,然后根据不同的文件类型去找不同的设备驱动,继而进行读写或者输 入输出控制。

目录
相关文章
|
11月前
|
Linux 开发工具
7种比较Linux中文本文件的最佳工具
7种比较Linux中文本文件的最佳工具
7种比较Linux中文本文件的最佳工具
|
6月前
|
Java Unix Go
【Java】(8)Stream流、文件File相关操作,IO的含义与运用
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。!但本节讲述最基本的和流与 I/O 相关的功能。我们将通过一个个例子来学习这些功能。
268 1
|
9月前
|
存储 数据管理 Linux
区分Linux中.tar文件与.tar.gz文件的不同。
总之,".tar"文件提供了一种方便的文件整理方式,其归档但不压缩的特点适用于快速打包和解压,而".tar.gz"文件通过额外的压缩步骤,尽管处理时间更长,但可以减小文件尺寸,更适合于需要节约存储空间或进行文件传输的场景。用户在选择时应根据具体需求,考虑两种格式各自的优劣。
1493 13
|
10月前
|
安全 Linux
Linux赋予文件000权限的恢复技巧
以上这些步骤就像是打开一扇锁住的门,步骤看似简单,但是背后却有着严格的逻辑和规则。切记,在任何时候,变更文件权限都要考虑安全性,不要无谓地放宽权限,那样可能
292 16
|
11月前
|
Linux
【Linux】 Linux文件I/O常见操作技巧
以上就是Linux文件I/O操作的一些技巧,接纳它们,让它们成为你在Linux世界中的得力伙伴,工作会变得轻松许多。不过记住,技巧的运用也需要根据实际情况灵活掌握,毕竟,最适合的才是最好的。
302 28
|
10月前
|
XML JSON Go
Go语言中的文件与IO:JSON、CSV、XML处理
本文介绍了 Go 语言中对 JSON、CSV 和 XML 三种常见数据格式的处理方法。通过标准库 `encoding/json`、`encoding/csv` 和 `encoding/xml`,可以实现结构体与数据格式之间的序列化与反序列化。JSON 适合 Web API 和前后端通信,因其清晰易读;CSV 适用于表格数据和轻量级交换;XML 则支持复杂嵌套结构,常用于配置文件和 SOAP 协议。文中提供代码示例,涵盖基本使用、嵌套结构处理及实战建议,帮助开发者高效操作这些格式。
|
10月前
|
存储 Linux 数据处理
深入剖析Linux中一切即文件的哲学和重定向的机制
在计算机的奇妙世界中,Linux的这套哲学和机制减少了不同类型资源的处理方式,简化了抽象的概念,并蕴藏着强大的灵活性。就像变戏法一样,轻轻松松地在文件、程序与设备之间转换数据流,标准输入、输出、错误流就在指尖舞动,程序的交互和数据处理因此变得既高效又富有乐趣。
173 4
|
10月前
|
Unix Go
Go语言中的文件与IO:文件读写
本文介绍了 Go 语言中文件操作的基础方法,涵盖打开与关闭文件、读取和写入文件内容、追加写入以及复制文件等功能。通过 `os`、`bufio` 和 `io` 等标准库包,提供了高效且灵活的实现方式,如使用 `os.ReadFile` 读取整个文件、`bufio.Scanner` 逐行读取、`os.Create` 创建文件以及 `io.Copy` 复制文件内容。同时强调了错误处理的重要性,例如使用 `defer` 确保文件关闭,并推荐注意文件权限设置(如 UNIX 系统中的 `0644`)。最后以表格形式总结了常用操作及其推荐方法,便于快速查阅和应用。
|
10月前
|
Go 数据处理
Go语言中的文件与IO:bufio 和 scanner
Go 标准库中的 `bufio` 包高效读写功能,适用于文件和数据处理。`bufio.Reader` 支持按行或分隔符读取,`bufio.Writer` 提供高性能写入并需调用 `Flush()` 确保数据写入。`bufio.Scanner` 是处理文本文件(如日志、配置)的利器,可按行、单词等分割内容。本文详解其用法,并给出实践建议,如统计字符数、模拟 `tail -f` 和词频分析等。
|
11月前
|
Ubuntu Linux
"unzip"命令解析:Linux下如何处理压缩文件。
总的来说,`unzip`命令是Linux系统下一款实用而方便的ZIP格式文件处理工具。本文通过简明扼要的方式,详细介绍了在各类Linux发行版上安装 `unzip`的方法,以及如何使用 `unzip`命令进行解压、查看和测试ZIP文件。希望本文章能为用户带来实际帮助,提高日常操作的效率。
2511 12