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 行,关闭文件,会将缓冲区暂存的数据写入到文件中去

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

相关推荐
烛.照1031 小时前
宝塔安装完redis 如何访问
linux·数据库·redis·缓存
未知陨落1 小时前
冯诺依曼系统及操作系统
linux·操作系统
纪伊路上盛名在1 小时前
ML基础-Jupyter notebook中的魔法命令
linux·服务器·人工智能·python·jupyter
躺不平的理查德2 小时前
Shell特殊位置变量以及常用内置变量总结
linux·运维·服务器
康王有点困2 小时前
(1)Linux高级命令简介
linux·运维·服务器
乙卯年QAQ2 小时前
【linux】linux缺少tar命令/-bash: tar:未找到命令
linux·运维·bash
向上的车轮2 小时前
OpenEuler学习笔记(十四):在OpenEuler上搭建.NET运行环境
linux·笔记·学习·.net
千航@abc3 小时前
vim如何解决‘’文件非法关闭后,遗留交换文件‘’的问题
linux·编辑器·vim
_Eden_5 小时前
Haproxy介绍及学习
linux·学习·haproxy
Golinie8 小时前
【C++高并发服务器WebServer】-9:多线程开发
linux·服务器·c++··多线程开发