Linux学习笔记之文件

news/2025/2/25 8:08:54

1.文件

        1.1文件属性

        当我们创建文件时,文件就有了对应的属性,可以用mkdir创建目录,touch创建普通文件。用ls -al查看文件属性。

        从上图可以看出目录或者文件的所有者,所属组,其他人权限,创建时间等信息。由此我们便可以得到,一个结论,文件创建出来,即使我们没有写入任何的数据,他也是有大小的。使用stat可以查看文件的详细信息。

stat test.c

        这里大小显示为0并不是没有占内存,而是大小不足一字节,所以显示为0.

                                                文件=文件内容+属性

1.2 文件存储位置

        当文件没有被打开使用时,如果把他放他被放置在系统的磁盘中,但当文件打开时,他就会被加载到内存中。CPU只会与内存进行数据处理,使用文件前必须打开文件说的也就是把文件从磁盘加载到内存中,让CPU进行数据处理

1.3 文件与进程关系

        当我们在修改文件时,在Windows中会默认打开记事本,在Linux中使用vim或者nano。实际上我们不会之间修改文件,而是通过软件修改,其实就是通过进程修改文件。我们要学习文件管理就是在学习OS进程管理与文件管理之间的关系。

1.4如何管理文件

        一个进程可以打开多个文件,多个进程可以打开很多文件,在OS中,这些文件分布在内存的各个地方,为了管理这些文件,Liunx必定会 先描述,在组织。即在使用struct结构体包含文件信息,然后再组织管理起来。如下图

        在Liunx中学习文件操作,就是学习进程管理与文件管理之间的关系。

2.C语言文件操作

        在C语言中,可以使用fopen打开文件,fwrite,fputs,fprintf等写入文件。

2.1 fopen

        

        path参数是文件地址,可以采用绝对地址,也可以采用想对地址。第二个参数是文件打开方式。函数失败返回空指针。

2.1.1 文件打开方式

        文件打开方式主要有6种,a,w,r及其附加类

  • r  以只读方式打开文件,(不可以修改文件)从文件开头读取。
  • r+ 以读写方式打开文件,从文件开头读取。
  • w 以写方式打开文件,文件存在清除,不存在创建新文件,从文件开头写入
  • w+ 以写方式打开文件,文件存在清除,不存在创建新文件,可以读取文件内容,从文件开头写入
  • a 以追加写入方式打开文件,文件不存在则创建,从文件结尾写入
  • a+ 以追加读取写入方式打开文件,文件不存在则创建,从文件结尾写入。但读取从文件开头开始读取

        总而言之,C语言提供了丰富的文件接口使用。不同场景下使用合适的方式。

#include<stdio.h>


int main()
{
    FILE * fp=fopen("hello.txt","w");//不加路径则默认为当前路径下


    fprintf(fp,"%s","hello files!\n");

    fclose(fp);


    return 0;
}

        运行上述程序后,会在当前目录下生成hello.txt文件。

2.2 fclose

       使用起来相对简单,只需要把文件指针传入即可。

         在打开文件后,必须要关闭文件,当我们在修改文件时,文件数据是在内存中的,如果直接结束进程,内存中的数据被释放,文件修改后的数据就可能不存在了。关闭文件实际上就是把在内存中的文件写入到磁盘当中去。

2.3 默认打开文件

        当C语言程序运行时,就会默认打开三个文件。

  • stdin 标准输入       (一般为键盘)
  • stdout 标准输出 (一般为显示器)
  • stderr 标准错误  (一般为显示器)

        2.3.1 键盘与显示器为什么是文件

                OS是软硬件资源的管理者,对上要提供良好的开发环境,对下要管理好硬件。实际上OS要管理好硬件,就是要做好对于数据的IO操作,从硬件读取数据,或者是向硬件写入数据。

        对于硬件来说,他会有许多,OS为了管理硬件,一定会先描述在组织,对下管理硬件资源。创建hardware_struct,里面有设备名称,硬件编号,以及函数指针等。其中的函数指针就是为了读写操作准备的。

        

        由此,当我们想要向硬件写入的时候,不必关注底层硬件设计,只需要使用write函数即可,剩下的交给硬件驱动。这就是Linux下的一切皆文件的实现方式。

        实际上驱动程序主要就是IO操作相关的函数,所以向电脑插入一个设备的时候,电脑首先就会查看有没有相关的驱动程序,如果没有就运行不了。我们之前学习的C语言函数就是对应上图的函数库操作。

3.系统文件操作

        根据之前的操作系统图,C语言函数一定是封装了系统调用接口的。OS不允许用户越过自己直接访问硬件。(当然单片机除外,简单的单片机没有OS)

3.1 open

        open就是操作系统提供的打开文件操作。

        int open(const char *pathname, int flags);该函数第一个参数是文件路径,第二个参数是标记位,可以选择对文件如何操作。有如下主要选项。

  • O_RDONLY:以只读方式打开文件。
  • O_WRONLY:以只写方式打开文件。
  • O_RDWR:以读写方式打开文件。
  • O_CREAT:如果文件不存在,则创建该文件。使用此标志时,需要提供第三个参数 mode 来指定文件的权限。
  • O_TRUNC:如果文件存在且以可写方式打开,则将文件截断为零长度。
  • O_APPEND:以追加方式打开文件,每次写操作都会将数据追加到文件末尾。

        上述标记位可以组合使用,用 | 分隔开。例如O_WRONLY | O_CREAT | O_TRUNC 就可以达到C语言fopen中W的效果,或者说C语言a,r,w就是open不同选项封装的。

3.1.1 返回值

            返回值是int,没有看错,返回值就是朴实无华的int。在Linux进程中我们必定要管理文件,但是一个int类型怎么指向一个文件?怎么根据int确定是那个文件。

        运行下述代码。

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



int main()
{
    
    int f1=open("text1",O_WRONLY|O_CREAT);
    int f2=open("text2",O_WRONLY|O_CREAT);
    int f3=open("text3",O_WRONLY|O_CREAT);
    int f4=open("text4",O_WRONLY|O_CREAT);
    int f5=open("text5",O_WRONLY|O_CREAT);

    printf("f1:%d f2:%d f3:%d f4:%d f5:%d",f1,f2,f3,f4,f5);

    return 0;
}

        我们可以发现如果我们连续打开文件,这是一连串的数字从3开始。计算机中有什么结构有如此规整的数字么?答案显然是数组,至于为什么从3开始,因为我们每个进程默认打开三个文件,标准输入,标准输出,标准错误。

        实际上进程就是使用数组来管理文件的,如下图。

        

        3.1.2 标记位如何实现

        实际上flags就是个32位的位图,每个O_RDONLY,O_WRONLY都是宏定义,且是某个比特位为1的特殊值。如下图

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
    printf("%d %d %d %d\n",O_RDONLY,O_WRONLY, O_CREAT,O_TRUNC);

    return 0;
}

      |实际上就是按位或,有1为1,这样在传入参数后,可以根据每个比特位的情况来实现不同的功能,而避免写过多的函数。

3.1.3 open

        在 C 语言里并没有像 C++ 那样的函数重载机制,C 语言要求函数名必须唯一。不过在 Linux 系统中,open 函数存在两种不同参数列表的形式,这并非是通过函数重载实现的,而是借助预处理器和编译器的协作来达成的。

        int open(const char *pathname, int flags, mode_t mode);前两个参数与之前一样,第三个参数是设置文件的权限。

        这里使用数字,实际上也是运用位图的思想,每个选项对应一个比特位。

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

int main() {
    
    open("hello.txt", O_TRUNC | O_WRONLY|O_CREAT, 0777);
    //这里0777表示8进制,二进制为 0 111 111 111

    return 0;
}

        运行上述程序,得到如下结果。

        但看起来与我们设置的777不符合,为0775,这是因为还有掩码umask作用,真实权限是将默认权限值与 umask 值按位取反的结果进行按位与运算。简单记位减去掩码就是真正的权限。权限=open设置-掩码)

        111 111 111 (默认权限)

        111 111 101 (取反后的掩码位)

         ---------------

        111 111 101 (计算结果)

3.2 close

        这个是Linux系统提供的接口,可以关闭文件,他的参数比较特殊是fd,就是文件在进程管理数组中的下标。关闭成功返回0,失败返回-1.

        标准输入,标准输出,标准错误也是文件,在数组下标为0,1,2.一定也可以被关闭。如下代码。

        

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



int main()
{
    
    close(2);
    int f1=open("text1",O_WRONLY|O_CREAT);
    int f2=open("text2",O_WRONLY|O_CREAT);
    int f3=open("text3",O_WRONLY|O_CREAT);
    int f4=open("text4",O_WRONLY|O_CREAT);
    int f5=open("text5",O_WRONLY|O_CREAT);

    printf("f1:%d f2:%d f3:%d f4:%d f5:%d\n",f1,f2,f3,f4,f5);

    return 0;
}

        可以发现下标从2开始。在运行下述程序,关闭0号文件。

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



int main()
{
    
    close(0);
    int f1=open("text1",O_WRONLY|O_CREAT);
    int f2=open("text2",O_WRONLY|O_CREAT);
    int f3=open("text3",O_WRONLY|O_CREAT);
    int f4=open("text4",O_WRONLY|O_CREAT);
    int f5=open("text5",O_WRONLY|O_CREAT);

    printf("f1:%d f2:%d f3:%d f4:%d f5:%d\n",f1,f2,f3,f4,f5);

    return 0;
}

        此时下标从1开始,由此我们可以得出下标的分配是从最小的没开始用的数组下标开始


http://www.niftyadmin.cn/n/5865233.html

相关文章

前端防重复请求终极方案:从Loading地狱到精准拦截的架构升级

&#x1f525; 事故现场还原&#xff1a;疯狂点击引发的血案 凌晨1点23分&#xff0c;监控系统突然告警&#xff1a; &#x1f4c9; 服务器CPU飙升至98% &#x1f5c3;️ 数据库出现3000脏数据 &#x1f4a5; 用户端弹出上百个错误弹窗 事故原因&#xff1a;黑产脚本通过0.5秒…

科普:HTTP端口80和HTTPS端口443

你会发现&#xff0c;有的网址不带端口号&#xff0c;怎么回事&#xff1f; HTTP协议默认端口&#xff1a;HTTP协议的默认端口是80。当用户在浏览器中输入一个没有指定端口的以http://开头的网址时&#xff0c;浏览器会自动使用80端口与服务器建立连接&#xff0c;进行超文本数…

【linux】文件与目录命令 - awk

文章目录 1. 基本用法2. 常用参数3. 用法举例4. 注意事项 awk 是一款强大的文本处理工具&#xff0c;用于逐行读取文件&#xff0c;根据指定规则对每行内容进行格式化处理和分析。它支持复杂的逻辑运算、正则表达式和条件控制。 1. 基本用法 语法&#xff1a; awk [选项] 脚本 …

【LeetCode 热题100】48. 旋转图像以及旋转任意角度的算法思路及python代码

48. 旋转图像 给定一个 n n n n nn 的二维矩阵 m a t r i x matrix matrix 表示一个图像。请你将图像顺时针旋转 90 90 90 度。你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&…

【C++设计模式】 单例设计模式:重要常用却并非完美之选

引言 设计模式在软件开发中扮演着至关重要的角色&#xff0c;然而&#xff0c;没有一种设计模式是完美无缺的&#xff0c;单例设计模式便是其中之一。它一直以来都备受争议&#xff0c;有人认为它是解决特定问题的有效方案&#xff0c;也有人觉得它存在诸多弊端。在实际应用中…

第5章 软件工程(一)

5.1 软件工程定义 软件工程是指应用计算机科学、数学及管理科学等原理&#xff0c;以工程化的原则和方法来解决软件问题的工程&#xff0c;其目的是提高软件生产率、 提高软件质量、降低软件成本。 5.2 软件需求 软件需求是指用户对系统在功能、行为、性能、设计约束等方面的…

玩转Docker | 使用Docker搭建Vikunja任务管理应用

玩转Docker | 使用Docker搭建Vikunja任务管理应用 前言一、 Vikunja介绍Vikunja 简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署Vikunja服务下载镜像创建容器检查容器状态检查服务端口安全设置四、访问Vikunja应用注册账号访问Vikunja主页五…

LabVIEW C编译支持工具库CCompileSupp.llb

路径&#xff1a;C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform\CCompileSupp.llb ​ 1. 工具库概述 定位&#xff1a;LabVIEW内置的C语言编译支持工具库&#xff0c;用于处理LabVIEW与C/C代码的混合编程接口&#xff0c;涵盖编译器配置、代码生成…