本文介绍: 1.运行linux操作系统用户空间程序2.内核程序运行内核空间应用程序运行在用户空间在终端执行命令ls,ps。。。。。。都是运行在用户空间3.内核空间和用户空间。

文章笔记来自于【速学Linux】手把手教你学嵌入式Linux C应用编程_哔哩哔哩_bilibili

一,什么linux应用程序

1.运行在linux操作系统用户空间的程序

2.内核程序运行在内核空间,应用程序运行在用户空间

终端执行命令ls,ps。。。。。。都是运行在用户空间

3.内核空间和用户空间

二,应用编程裸机编程驱动编程什么区别

三,如何编写linux应用程序

1.系统调用  【linux操作系统向应用层提供的接口system call ,是linux 应用层进入内核空间的入口】

2.库函数标准c库函数  【对系统调用封装

3.不要局限于编程语言 

四,文件I/O基础

1.什么文件I/O ?   【对文件输入输出操作,也就是文件的读/写操作

2.文件描述符

这相当于是每次打开一个文件,每个文件会分配一个文件描述符分配一个没有使用最小非负整数作为文件描述符】,相当于这个文件的标签一下,所有执行 IO 操作的系统调用都是通过文件描述符索引对应的文件,一个进程最多可以打开 1024 个文件,当文件被关闭时,对应的文件描述符会被释放,释放之后也就成为一个没有被使用的文件描述符了

3.打开/创建文件:open()函数

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

字符串类型用于标识需要打开创建的文件,可以包含路径绝对路径相对路径信息,譬如:”./src_file
当前目录下的
src_file
文件)、
“/home/dengtao/hello.c
等;如果
pathname
一个符号链接,会对其进行解引用
flags

调用
open
函数需要提供的标志,包括文件访问模式标志以及其它文件相关标志,这些标志使
用宏定义进行描述

Linux 中 已经定义好的宏,不同的宏定义表示不同权限

 

4.写文件:write()函数

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

文件描述符。关于文件描述符,前面已经给大家进行了简单讲解这里不再重述!我们需要将进
行写操作的文件所对应的文件描述传递
write
函数
count

指定写入的字节数。
返回值
如果成功返回写入的字节数(
0
表示未写入任何字节),如果此数字小于
count
参数,这不
错误,譬如磁盘空间已满,可能会发生这种情况;如果写入出错,则返回
-1
读文件和写文件存在一个读写位置读写指针】,假设初始打开的文件才开始是在0的位置,当写入100字节,指针往后移动100字节,且
读写指针是共用指针然后就会从100字节出开始读取
5.读文件: read()函数
ssize_t read(int fd, void *buf, size_t count);
fd

文件描述符。与
write
函数
fd
参数意义相同
count

指定需要读取的字节数。
返回值
如果读取成功返回读取到的字节数,实际读取到的字节数可能会小于
count
参数指定的字节
数,也有可能会为
0
,譬如进行读操作时,当前文件位置偏移量已经到了文件末尾。实际读取到的字节数少
于要求读取的字节数,譬如在到达文件末尾之前有
30 个字节数据,而要求读取 100 个字节,则 read 读取
功只能返回 30;而下一次调用 read 读,它将返回 0
(文件末尾

6. 关闭文件: close()函数

int close(int fd);
fd

文件描述符,需要关闭的文件所对应的文件描述符。
返回值
如果成功返回
0
,如果失败则返回
-1

学习示例

1.打开文件,写入内容

#include <sys/types.h&gt;
#include <sys/stat.h&gt;
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
    int fd;
    int ret;
    fd = open("./test.txt",O_WRONLY | O_CREAT | O_EXCL,0644);
    if(-1 == fd){
        printf("open error");
        return 1;
    }
    printf("open okrn");
    ret = write(fd, "Hello world",11);
    if(-1 == ret){
        printf("write errorrn");
        close(fd);
        return 1;
    }
    printf("write %d Bytes OK",ret);

    close(fd);
    return 0;
}

 运行结果

 2.读取文件内容

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>


int main()
{
    int fd;
    char buf[125] = {0};
    int ret;
    fd = open("./test.txt",O_RDONLY);   
    if(-1 == fd){
        printf("open error");
    }
    printf("open ok");
    ret = read(fd, buf, 11);
    if(-1 == ret){
        printf("read errorrn");
        close(fd);
        return 1;
    }
    printf("read %d bytes: %s",ret,buf);
    close(fd);
    return 0;
}

运行结果

7.调整读写位置偏移:lseek()函数

off_t lseek(int fd, off_t offset, int whence);
fd

文件描述符。
offset

偏移量,以字节为单位
whence

用于定义参数
offset
偏移量对应的参考值,该参数为下列其中一种(宏定义):

SEEK_SET
读写偏移量指向
offset
字节位置处(从文件头部开始算

SEEK_CUR
:读写偏移量指向当前位置偏移量
+ offset
字节位置处,
offset
可以为正、也可以为
负,如果是正数表示往后偏移,如果是负数则表示往前偏移

SEEK_END
:读写偏移量将指向文件末尾
+ offset
字节位置处,同样
offset
可以为正、也可以为负,
如果是正数表示往后偏移、如果是负数则表示往前偏移

 五,深入探究文件I/O

1.linux系统如何进行文件管理

文件储存在硬盘上,硬盘最小存储单位叫做“扇区”(Sector),每个扇区储存 512 字节(相当于 0.5KB),操作系统读取硬盘时候,以“块”为单位进行文件读取。【“块”的大小,最常

见的是 4KB,即连续八个 sector 组成一个 block

静态文件:文件存放磁盘内叫做静态文件

inode: 指向文件存放在磁盘的位置

pcb: 进程控制块,管理进程,譬如用于记录进程状态信息、运行特征

 2.错误处理

1.errno

2.strerror函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
    int fd1;
    fd1 = open("./test111.c",O_RDONLY);
    if(-1 == fd1)
    {
        printf("%sn", strerror(errno));
        return -1;
    }
    
    return 0;
}

 运行结果

3.perror:可以加入自己打印信息

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
    int fd1;
    fd1 = open("./test111.c",O_RDONLY);
    if(-1 == fd1)
    {
        perror("open error");
        return -1;
    }
    
    return 0;
}

运行结果

 3.空洞文件

概念:当一个文件本身只有4k大小,但是当前的通过lseek从文件头部偏移6000个字节,开始写入内容,导致4096-6000字节间没有内容出现了“空洞”,也就是空洞文件

使用场景:一个文件可以从不同地址开始写入,不再是单线程从头开始写入,多个线程同时写入,利用多线程的优势

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
static unsigned char buf[4096];
int main(void)
{
    int fd;
    int ret;
    fd = open("./test.txt",O_WRONLY | O_CREAT | O_EXCL,0644);
    if(-1 == fd)
    {
        perror("open error");
        return 1;        
    }
    ret = lseek(fd, 4096, SEEK_SET);
    if(-1 == ret)
    {
        perror("lseek error");
        close(fd);
        return 1;
    }

    ret = write(fd, buf, 4096);
    if(-1 == ret)
    {
        printf("write error");
        close(fd);
        return 1;
    }
    close(fd);
    return 0;


}

运行结果:

ls 命令:查看到大小是文件的逻辑大小   
du 命令:查看到大小是文件实际占用存储块的大小

4.O_TRUINC和O_APPEND

O_TRUINC将文件原本的内容全部丢弃,文件大小变为 0
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
    int fd;
    fd = open("./test.txt",O_WRONLY | O_TRUNC);
    if(-1 == fd)
    {
        perror("open error");
        close(fd);
        return 1;        
    }    
    close(fd);
    return 0;
}

运行结果:

O_APPEND当每次使用 write()函数对文件进行写操作时,都会自动把文件当前位置偏移量移动到文件末尾
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(void)
{
    int fd;
    int ret;
    fd = open("./test.txt",O_WRONLY | O_APPEND);
    if(-1 == fd)
    {
        perror("open error");
        close(fd);
        return 1;        
    }    
    ret = write(fd,"hello world",11);
    if(-1 == ret)
    {
        perror("write error");
        close(fd);
        return 1;
    }
    
    close(fd);
    return 0;
}

运行结果:

open可以多次打开一个文件,产生多个文件描述符,也就是存在多个文件表,,但是都指向同一个文件,但是只能产生一个动态文件,以及同一个inode。对于打开的每一个fd.都要依次关闭。

5.文件描述符的复制

int dup(int oldfd);                           复制文件描述符

int dup2(int oldfd, int newfd);        文件描述符的数可以自行决定

新的文件描述符和旧的指向同一个文件表,去完成任何操作

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int fd1, fd2;
    int ret;
    fd1 = open("./test_file", O_RDWR | O_CREAT | O_EXCL,
    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    if (-1 == fd1) {
        perror("open error");
        exit(-1);
    }
    /* 复制文件描述符 */
    fd2 = dup2(fd1, 100);
    if (-1 == fd2) {
        perror("dup error");
        ret = -1;
        goto err1;
    }
    printf("fd1: %dnfd2: %dn", fd1, fd2);
    ret = 0;
    close(fd2);
err1:
    /* 关闭文件 */
    close(fd1);
    exit(ret);
}

运行结果

6.文件共享

概念同一个文件(譬如磁盘上的同一个文件,对应同一个 inode多个独立的读写体同时进行 IO 操作

常见三种文件共享实现方式

(1)同一个进程多次调用open函数打开同一个文件,多个文件描述符指向不同的文件表,但是多个文件表中inode指针指向inode节点

(2)不同进程分别打开同一个文件

(3)同一个进程通过dup(dup2)函数对文件描述符进行复制 

 7.原子操作与竞争冒险

竞争冒险:进程获得cpu的使用权完全是由操作系统决定的,先后顺序不可预期的

原子操作:多个步骤组成的一个操作,要么执行要么必须执行完所有操作,不可以只执行所有步骤的一个子集

(1)O_APPEND
实现原子操作
移动到文件末尾然后读写文件
(2)pread()
和 pwrite()
移动偏移位置,然后读写文件

(3)
创建一个文件O_EXCL
判断是否有文件 然后创建文件

 8.截断文件

ftruncate():使用文件描述符 fd 来指定目标文件大小,目标文件必须具有可写权限

truncate():
使用
文件路径path

来指定目标文件大小
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{  
    int fd;
    int ret;
    fd = open("./test.txt", O_RDONLY | O_WRONLY);
    if(-1 == fd)
    {
        perror("open error");
        return 1;        
    }
    ret = ftruncate(fd, 4096);
    if(ret == -1)
    {
        perror("sss");
        return 1;
    }
    close(fd);
    return 0;
}

运行结果:

9.fcntl和ioctl函数

fcntl()函数():对文件描述符做一系列控制操作

int fcntl(int fd, int cmd, ... /* arg */ )

复制文件描述符(
cmd=F_DUPFD

cmd=F_DUPFD_CLOEXEC)

获取
/
设置文件描述符标志(
cmd=F_GETFD

cmd=F_SETFD

获取
/
设置文件状态标志(
cmd=F_GETFL

cmd=F_SETFL

获取
/
设置异步
IO
所有权
cmd=F_GETOWN

cmd=F_SETOWN

获取
/
设置记录锁(
cmd=F_GETLK

cmd=F_SETLK

ioctl()函数:是一个文件 IO 操作的杂物箱,可以处理的事情非常杂、不统一

int ioctl(int fd, unsigned long request, ...);

原文地址:https://blog.csdn.net/weixin_63032791/article/details/134538084

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_45998.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注