当前位置: 首页 > article >正文

Linux文件基本操作

Linux 的设计哲学

在 Linux 中,一切皆文件!

什么是文件?

文件是具有永久存储性,按特定字节顺序组成的命名数据集

文件可分为:文本文件,二进制文件

文本文件:每个文件存放一个 ASCII 码

  • 存储量大,速度慢,便于对字符操作

二进制文件:数据按照在内存中的存储形式原样存放

  • 存储量小,速度快,便于存放中间结果

Linux 文件编程

在 Linux 中,除了常规文件,目录,设备,管道等,也属于文件

ASCII C 文件编程

标准 C 文件接口建立于 Linux 原生文件接口之上,使用缓冲区机制提高效率

缓冲区是一片特殊的内存空间,用于暂存文件中的数据

  • 读:一次性将大量的数据读入缓冲区 (后续再从缓冲区中拿数据)
  • 写:可先把数据写入输入缓冲区 (缓冲区满之后再把数据一次性写入文件)
  • 缓冲区的引入是为了避免频繁的磁盘操作,提高文件读写的整体效率

深入 ASCII C 文件编程

由于引入了缓冲区,ASCII C 文件编程是一种基于数据流的编程

ASCII C 文件编程接口

ASCII C 文件打开模式

文本文件写示例

ASCII C 文件 "读写移动指针"

int fseek(FILE* stream, long offset, int whence);

  • 移动文件读写指针,whence => SEEK_SET,SEEK_END,SEEK_CUR

long ftell(FILE* stream);

  • 获取当前读写指针的位置 (对于文件起始位置)

void rewind(FILE* stream);

  • 将读写指针置于文件起始位置,(void)fseek(stream, 0L, SEEK_SET)

二进制文件读写示例

ASCII C 文件编程初体验

test1.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>

int main() 
{
    FILE* fp = NULL;
    char student[50] = {0}; 
    int i = 0;
    
    if( (fp = fopen("input.txt", "w")) == NULL )
    {
        perror("open file error...\n");
        exit(1);
    }
    
    for(i=0; i<3; i++)
    {
        printf("input name:");
        scanf("%s", student);
        fputs(student, fp);
        fputs("\n", fp);
    }
    
    fclose(fp);
    
    return 0;
}

第 13 行,我们以写的方式打开一个文本文件

第 23 行,通过 fputs(...) 将字符串写入到文本文件中

程序运行结果如下图所示:

test2.c

#include <stdio.h>
#include <stdlib.h>

#define N   3

struct student
{
  long num;
  char name[16];
  int age;
};

int main()
{
    int i = 0;
    struct student s = {0};
    FILE* fp = NULL;

    if( (fp = fopen("student.dat", "wb+")) == NULL )
    {
        perror("open file error...\n");
        exit(1);
    }

    for(i=0; i<N; i++)
    {
        printf("Number: %d\n", i + 1);
        printf("ID:");
        scanf("%ld", &s.num);
        printf("Name:");
        scanf("%s", s.name);
        printf("Age:");
        scanf("%d", &s.age);
        printf("\n");
        
        fwrite(&s, sizeof(s), 1, fp);
    }

    rewind(fp);
      
    for(i=0; i<N; i++)
    {
        fread(&s, sizeof(s), 1, fp);
        
        printf("%ld %s %d\n", s.num, s.name, s.age);
    }

    fclose(fp);
    
    return 0;
}

第 19 行,我们以写入并新建文件的方式打开一个二进制文件

第 25 - 37 行,我们通过 scanf 来填充结构体的内容,并通过 fwrite 写入到二进制文件中

由于文件读写指针会在我们进行文件写入操作后,偏移位置在文件的末尾,所以在接下来我们需要读取文件内容的时候,可以使用 rewind(...) 函数,将文件读写指针偏移到文件的起始位置处,再进行读取

程序运行结果如下图所示:

ASCII 文件缓冲区类型

全缓冲区:默认缓冲器大小为 BUFSIZ,具体大小与系统相关

  • 缓冲区满 或 调用 fflush() 才通过系统调用将数据写入磁盘 (设备)

行缓冲区:默认缓冲区大小为 128 字节,具体大小与系统有关

  • 遇见 换行符 或 缓冲区满 或 调用 fflush() 后通过系统调用将数据写入磁盘 (设备)

无缓冲区:不对数据进行缓冲

  • 相当于直接使用系统调用 write(),数据立即写入磁盘 (设备)

自定义文件缓冲区

缓冲区代码示例

文件缓冲区编程实验

test3.c


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <memory.h>

int main() 
{
    FILE* fp = NULL;
    char buf[128] = {0}; 
    char* ps = "Delphi\nTang";
    
    if( (fp = fopen("input.txt", "w")) == NULL )
    {
        perror("open file error...\n");
        exit(1);
    }
    
    setvbuf(fp, buf, _IOLBF, sizeof(buf));
    
    fwrite(ps, sizeof(*ps), strlen(ps), fp);
    
    printf("ps = %s\n", buf);
    
    fclose(fp);
    
    return 0;
}

第 19 行,我们通过 setvbuf(...) 函数将 input.txt 这个文件的缓冲类型设置为行缓冲,缓冲区为我们定义的 buf,缓冲区大小为 128 字节

第 21 行,我们通过 fwrite(...) 将字符串写入到文件中,由于我们设置了行缓冲,数据会先写入到缓冲区中,当遇到换行符后,会将缓冲区的 "Delphi" 字符串写入到文件中,字符串 "Tang" 还暂存在缓冲区中

第 25 行,我们调用了 fclose(...),把缓冲区中的字符串 "Tang" 也写入到文件中

程序运行结果如下图所示:

缓冲区的内容为 "Tanghi",是因为 "hi" 为脏数据,是将 "Delphi" 写入到缓冲区时保留下来的

test4.c


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


struct student
{
    long num;
    char name[16];
    int age;
};

int main(int argc, char* argv[]) 
{
    FILE* fp = NULL;
    char buf[BUFSIZ] = {0};
    struct student s = {999, "tang", 888};
    struct student* ps = NULL;
    
    if( (fp = fopen("input.txt", "w")) == NULL )
    {
        printf("open file error: %d...\n", __LINE__);
        exit(1);
    }
    
    printf("BUFSIZ = %d\n", BUFSIZ);
    
    setvbuf(fp, buf, _IOFBF, sizeof(buf));
    
    fwrite(&s, sizeof(s), 1, fp);
    
    fclose(fp);
    
    ps = (void*)buf;
    
    printf("num = %ld,  name = %s,  age = %d\n", ps->num, ps->name, ps->age);
    
    /
    
    if( (fp = fopen("input.txt", "r")) == NULL )
    {
        printf("open file error: %d...\n", __LINE__);
        exit(2);
    }
    
    setvbuf(fp, buf, _IOFBF, sizeof(buf));
    
    memset(&s, 0, sizeof(s));
    memset(buf, 0, sizeof(buf));
    
    fread(&s, sizeof(s), 1, fp);
    
    printf("num = %ld,  name = %s,  age = %d\n", s.num, s.name, s.age);
    
    fclose(fp);
    
    ps = (void*)buf;
    
    printf("num = %ld,  name = %s,  age = %d\n", ps->num, ps->name, ps->age);
    
    return 0;
}

第 31 行,打印系统预定义的文件默认缓冲区大小的宏

第 33 行,设置文件缓冲区为全缓冲

第 35 行,我们将结构体 s 的内容写入到文件中,由于设置的是全缓冲,写入的结构体大小没有超过缓冲区大小,所以会先将数据暂存在缓冲区 buf 中

第 37 行,关闭文件,会将缓冲区暂存的数据写入到文件中去

程序运行结果如下图所示:


http://www.kler.cn/a/523447.html

相关文章:

  • shiro学习五:使用springboot整合shiro。在前面学习四的基础上,增加shiro的缓存机制,源码讲解:认证缓存、授权缓存。
  • 快速分析LabVIEW主要特征进行判断
  • 128周二复盘(164)学习任天堂
  • c++:vector
  • 设计模式的艺术-策略模式
  • CTF从入门到精通
  • AIP-133 标准方法:Create
  • 一文读懂DeepSeek-R1论文
  • 游戏引擎分层架构与总体管线
  • 蓝桥杯python语言基础(4)——基础数据结构(上)
  • 【esp32-uniapp】uniapp小程序篇02——引入组件库
  • 【愚公系列】《循序渐进Vue.js 3.x前端开发实践》029-组件的数据注入
  • 基于SpringBoot电脑组装系统平台系统功能实现五
  • .NET MAUI 入门学习指南
  • 从AD的原理图自动提取引脚网络的小工具
  • 进程通讯——类型和发展
  • 一个局域网通过NAT访问另一个地址重叠的局域网(IP方式访问)
  • 【YOLOv11改进- 注意力机制】YOLOv11+SCSA注意力机制(2024): 最新空间和通道协同注意力,助力YOLOv11有效涨点;包含二次创新
  • 力扣动态规划-13【算法学习day.107】
  • Julia Distributed(分布式计算)详解
  • 浅谈Linux的发展
  • iOS开发设计模式篇第二篇MVVM设计模式
  • ReactNative react-devtools 夜神模拟器连调
  • 【云安全】云原生-K8S-搭建/安装/部署
  • 【LeetCode: 941. 有效的山脉数组 + 双指针】
  • 学习数据结构(1)时间复杂度