首页 > 其他分享 >2024-02-20-物联网C语言(10-文件)

2024-02-20-物联网C语言(10-文件)

时间:2024-02-20 18:12:02浏览次数:26  
标签:02 10 20 文件 int fp FILE printf 指针

10. 文件

10.1 文件的概念

文件用来存放程序、文档、音频、视频数据、图片等数据的。文件就是存放在磁盘上的,一些数据的集合。
在 windows 下可以通过写字板或记事本打开文本文件对文件进行编辑保存。写字板和记事本是微软程序员写的程序,对文件进行打开、显示、读写、关闭。
作为一个程序员,必须掌握编程实现创建、写入、读取文件等操作。
对文件的操作是经常要用到的知识,比如:写飞秋软件传送文件等。

10.2 文件的定义

磁盘文件:(我们通常认识的文件)

指一组相关数据的有序集合,通常存储在外部介质(如磁盘)上,使用时才调入内存。

设备文件:

在操作系统中把每一个与主机相连的输入、输出设备看作是一个文件,把它们的输入、输出等同于对磁盘文件的读和写。

  1. 键盘:标准输入文件
  2. 屏幕:标准输出文件
  3. 其它设备:打印机、触摸屏、摄像头、音箱等

在 Linux 操作系统中,每一个外部设备都在/dev 目录下对应着一个设备文件。

在程序中要想操作设备,就必须对与其对应的/dev,下的设备文件进行操作。

标准io库函数对磁盘文件读取/存储过程

image-20240220141335352

文件缓冲区是库函数申请的一段内存,由库函数对其进行操作,程序员没有必要知道存放在哪里,只需要知道对文件操作的时候的一些缓冲特点即可。 举例:放苹果到办公室的例子

10.2.1 行缓冲

标准io库函数,往标准输出(屏幕)输出东西的时候是行缓冲的。

所谓的行缓冲就是缓冲区碰到 换行符 的时候才刷新缓冲区

如果不刷新缓冲区,无法对文件执行读写操作

1. 换行符刷新行缓冲区;
printf("hello world!\n");

2. 程序正常结束刷新缓冲区;
printf("hello world!");
return 0;

3. 使用fflush刷新缓冲区;
printf("hello world!");
// fflush 刷新函数,可以刷新指定的缓冲区
// stdout 标准输出,就是对终端进行写操作
fflush(stdout);

10.2.2 全缓冲

标准 io库函数 ,往普通文件读写数据的,是全缓冲的;

碰到换行符也不刷新缓冲区,即缓冲区满了,才刷新缓冲区。

刷新缓冲区的情况:

  1. 缓冲区满了,刷新缓冲区
  2. 人为刷新缓冲区 fush(文件指针)
  3. 程序正常结束 会刷新缓冲区

10.2.3 无缓冲

在读写文件的时候通过系统调用io(read write),对文件进行读写数据。

此时是无缓冲的,即写数据会立马进入文件,读数据会立马进入内存

10.2.4 写文件的流程

应用程序空间 →内核空间 → 驱动程序 →硬盘上

应用程序和内核程序运行在不同的空间里,目的是保护内核
设置缓冲区的目的:通过缓冲可以减少进出内核的次数,以提高效率。

10.3 磁盘文件分类

文件通常是磁盘上一段命名的存储区,计算机的存储在物理上是二进制的;

所以物理上所有的磁盘文件本质上都是一样的:以字节为单位进行顺序存储

从用户或者操作系统使用的角度(逻辑上)把文件分为:

  1. 文本文件:基于字符编码的文件
  2. 二进制文件:基于值编码的文件

10.3.1 文本文件

基于字符编码,常见编码有 ASCI、UNICODE 等,一般可以使用文本编辑器直接打开

例如:

  1. 数 5678 的以 ASCII 存储形式为ASCI码:00110101 00110110 0011011100111000

  2. 歌词文件(lrc):文本文件

10.3.2 二进制文件

基于值编码,自己根据具体应用,指定某个值的意思,把内存中的数据按其在内存中的存储形式原样输出到磁盘上

一般需要自己判断或使用特定软件分析数据格式

例如:

  1. 5678 的存储形式为二进制码:00010110 00101110

  2. 音频文件(mp3):二进制文件

  3. 图片文件(bmp)文件,一个像素点由两个字节来描述*****####H#&&&&&

    *代表红色的值
    #代表绿色的值
    &代表蓝色的值

进制文件以位来表示一个意思

10.3.3文本文件、二进制文件对比

  1. 译码

    文本文件编码基于字符定长,译码容易些;二进制文件编码是变长的,译码难一些(不同的二进制文件格式,有不同的译码方式)

  2. 空间利用率
    二进制文件用一个比特来代表一个意思(位操作),而文本文件任何一个意思至少是一个字符。二进制文件,空间利用率高。

  3. 可读性
    文本文件用通用的记事本工具就可以浏览,二进制文件需要一个具体的文件解码器,比如读 BMP 文件,必须用读图软件

文件在硬盘上存储的时候,物理上都是用二进制来存储的。标准 io 库函数,对文件操作的时候,不管文件的编码格式(字符编码、或二进制),而是按字节对文件进行读写,所以又叫流式文件,即把文件看成一个字节流

10.4 文件指针

文件指针就是用于标识一个文件的,所有对文件的操作都是用对文件指针进行操作的。

10.4.1 定义

// 定义文件指针的一般形式为:
	FILE* 指针变量标识符;
	本质上文件指针是一个结构体指针,结构体中包含了当前文件的很多信息,但是在实际编程时不需要关系结构体中的成员,只需要使用文件指针即可

对文件操作的步骤:

  1. 对文件进行读写等操作之前要打开文件得到文件指针
  2. 可以通过文件指针对文件进行读写等操作
  3. 读写等操作完毕后,要关闭文件,关闭文件后,就不能再通过此文件指针操作文件了

c语言中有三个特殊的文件指针无需定义,在程序中可以直接使用

  1. stdin : 标准输入 默认为当前终端(键盘)我们使用的scanf、getchar函数默认从此终端获得数据
  2. stdout :标准输出 默认为当前终端(屏幕)我们使用的printf、puts函数默认输出信息到此终端
  3. stderr: 标准错误输出设备文件 默认为当前终端(屏幕 )当我们程序出错使用perror函数时信息打印在此终端

10.4.2 打开文件

函数的定义:

FILE *fopen(const char *path, const char *mode);

函数说明:

fopen,函数的功能是打开一个已经存在的文件,并返回这个文件的文件指针(文件的标示)或者创建一个文件,并打开此文件,然后返回文件的标示

函数的参数:

参数 1:
1. 打开的文件的路径;
2. 绝对路径,从根目录开始的路径名称"/home/edu/test/test.txt";
3. 相对路径
    ../test/test.txt
    ..../test/test.txt
参数 2:
文件打开的方式,即以什么样的方式(只读、只写、可读可写等等)打开文件第二个参数的几种形式(打开文件的方式)
    r w a +

image-20240220151404077

#include <stdio.h>

int main(int argc, char const *argv[])
{
    /* code */
    FILE *fp;
    fp =fopen("./a.txt","w");// 如果文件存在则清空,不存在就新建
    if (fp == NULL){
        printf("FAIL TO FOPEN\n");
        return -1;
    }
    return 0;
}

10.4.3 关闭文件

函数的头文件: #include <stdio.h>
函数的定义:
		int fclose(FILE *fp);
函数的说明:关闭所代表的文件, 注意一个文件只能关闭一次,不能多次关闭。关闭文件之后就不能再文件指针对文件进行读写等操作;
返回值:
	成功返回 0
	失败返回非 0

注意:可以通过返回值,来判断关闭文件是否成功。

10.4.5 一次读写一个字符

fgetc
	#include <stdio.h>
	int fgetc(FILE *stream);
功能:从文件指针标识的文件中读取一个字符
参数:
	stream:指定的文件指针
返回值:
    成功:读取的字符
    失败:EOF
    如果文件读取完毕,也会返回EOF
fputc
#include <stdio.h>
int fputc(int c,FILE *stream);
功能:向文件指针标识的文件中写入一个字符参数:
	c:要写入的字符
	stream:指定的文件指针
返回值:
	成功:要写入的字符
	失败:EOF
#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    fp = fopen("./a.txt", "r");
    if (fp == NULL)
    {
        printf("file to open \n");
        return -1;
    }
    int c;
    while ((c = fgetc(fp)) != EOF)
    {
        printf("c = [%c] - %d\n", c, c);
    }

    return 0;
}

输出结果

c = [h] - 104
c = [e] - 101
c = [l] - 108
c = [l] - 108
c = [o] - 111
c = [ ] - 32
c = [w] - 119
c = [o] - 111
c = [r] - 114
c = [l] - 108
c = [d] - 100
#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    fp = fopen("./a.txt", "a+");
    if (fp == NULL)
    {
        printf("file to open \n");
        return -1;
    }
    
    fputc('\n',fp);
    fputc('y',fp);
    fputc('e',fp);
    fputc('s',fp);

    return 0;
}

a.txt

hello world 
yes

10.4.6 一次读写一个字符串

fgets 
#include <stdio.h)
char *fgets(char *s,int size,FILE *stream);
功能:从文件中读取内容参数:
	s:保存读取到的内容
	size:每次读取的最大个数
	stream:文件指针
返回值:
	成功:读取的数据的首地址
	失败:NULL
如果文件内容读取完毕,也返回NULL

说明:从 stream 所指的文件中读取字符,在读取的时候碰到换行符或者是碰到文件的末尾停止读取,或者是读取了 size-1个字节停止读取,在读取的内容后面会加一个\0作为字符串的结尾

fputs
#include <stdio.h>
int fputs(const char *s,FILE *stream);
功能:向文件写入数据;
参数
	s:要写入的内容
	stream:文件指针
返回值:
	成功:写入文件内容的字节数
	失败:EOF
#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    fp = fopen("./a.txt", "r");
    if (fp == NULL)
    {
        printf("file to open \n");
        return -1;
    }
    
    char buf[32] = "";
    fgets(buf,32,fp);
    printf("buf = %s \n",buf);
    return 0;
}

输出结果

// 碰到换行符,立即停止读取,所以只能读取一行内容
buf = hello world 
#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    fp = fopen("./a.txt", "a");
    if (fp == NULL)
    {
        printf("file to open \n");
        return -1;
    }

    fputs("yes I love c", fp);
    return 0;
}

a.txt

hello world 
yesyes I love c

10.4.7 读文件fread

函数的定义:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
函数的说明:
	fead,函数从 stream 所标示的文件中读取数据,一块是 size 个字节,共 nmemb,块,存放到ptr指向的内存里
返回值:
	实际读到的块数
int num;
num = fread(str,100,3,fp);
从fp所代表的文件中读取内容存放到 str 指向的内存中,读取的字节数为每块 100 个字节,共3块。
返回值 num:
1. 如果读到 300 个字节返回值 num为 3;
2. 如果读到了大于等于 200 个字节小于 300个字节: 返回值为 2;
3. 如果读到的字节数大于等于 100 个字节小于 200 个字节, 返回 1
4. 不到 100 个字节返回 0
#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    fp = fopen("./a.txt", "r");
    if (fp == NULL)
    {
        printf("file to open \n");
        return -1;
    }
    // 使用fread读取文件内容
    int num;
    char buf[128] = "";
    num = fread(buf, 5, 4, fp);
    printf("%s \n", buf);
    printf("num = %d \n", num);
    return 0;
}

输出结果

// 总共读取20个字节 (5*4)
hello world 
yesyes
num = 4

10.4.8 写文件fwrite

#include<std10.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:向文件中写入数据参数:
    ptr:要写入的数据
    size:一次写入的字节数
    nmemb:一共写入的次数
    stream:文件指针
返回值:
    成功:实际写入的次数
    失败:0
#include <stdio.h>

typedef struct
{
    /* data */
    int a;
    int b;
    char c;
} MSG;

int main(int argc, char const *argv[])
{
    FILE *fp;
    fp = fopen("./b.txt", "w+");
    if (fp == NULL)
    {
        printf("FAIL TO FOPEN\n");
        return -1;
    }

    MSG msg[4] = {1, 2, '3', 2, 5, 'a', 3, 6, '4',  4, 7, '5', 6, 7, '8'};
    fwrite(msg, sizeof(MSG), 4, fp);
    // 将文件的偏移量设置为文件的起始位置
    rewind(fp);

    MSG rev[4];
    fread(rev, sizeof(MSG), 4, fp);
    int i;
    for (i = 0; i < 4; i++)
    {
        printf("%d - %d -%c\n", rev[i].a, rev[i].b, rev[i].c);
    }

    return 0;
}

输出结果

1 - 2 -3
2 - 5 -a
3 - 6 -4
4 - 7 -5

10.4.9 格式化读写文件函数

函数调用:
    fprintf( 文件指针,格式字符串,输出表列);
    fscanf (文件指针,格式字符串,输入表列):
函数功能: 
	从磁盘文件中读入或输出字符
fprintf 和 printf函数类似:
	printf是将数据输出到屏幕上(标准输出);
    fprintf函数是将数据输出到文件指针所指定的文件中。
fscanf 和 scanf 函数类似:
    scanf是从键盘(标准输入)获取输入;
    fscanf是从文件指针所标示的文件中获取输入。
#include <stdio.h>

int main(int argc, char const *argv[])
{
    FILE *fp;
    char ch1 = 'a', ch2;
    int num1 = 50, num2;
    char string1[20] = "hello", string2[20];
    float score1 = 85.5, score2;
    fp = fopen("./c.txt", "w+");
    if (fp == NULL)
    {
        printf("FAIL TO OPEN\n");
        return -1;
    }
    // 使用fpintf向文件写入字符串
    fprintf(fp, "%c %d %s %f\n", ch1, num1, string1, score1);
    rewind(fp);
    // 使用fscanf获取文件内容
    fscanf(fp, "%c %d %s %f\n", &ch2, &num2, &string2, &score2);
    printf("%c %d %s %f\n", ch2, num2, string2, score2);
    fclose(fp);
    return 0;
}

输出结果

c.txt

a 50 hello 85.500000
a 50 hello 85.500000

10.4.10 随机读写

  1. rewind

    #include <stdio.h>
    void rewind(FILE *stream);
    功能:将文件位置定位到起始位置;
    参数:
    	stream:文件指针
    返回值:无
    
  2. ftell

    #include <stdio.h>
    long ftell(FILE *stream);
    功能:获取当前文件的偏移量;
    参数:
    	stream:文件指针
    返回值:
    	获取当前文件的偏移量
    
  3. fseek

    #include <stdio.h>
    int fseek(FILE *stream, long offset, int whence);
    功能:设置文件位置指针的偏移量;
    参数:
    	stream:文件指针
    	offset:偏移量,可正可负也可为0
    whence:相对位置
        SEEK_SET 文件起始位置
        SEEK_CUR 文件当前位置
        SEEK_END 文件末尾位置(最后一个字符后面一个位置)
    返回值:
        成功  0 
        失败 -1
        
    rewind(fp) <==> fseek(fp,0,SEEK_SET)
    

标签:02,10,20,文件,int,fp,FILE,printf,指针
From: https://www.cnblogs.com/hasaki-yasuo/p/18023738

相关文章

  • 2.20
    有人建议我把闲话写长一点好的,爱你,笔芯第一件事:假发到了只到了一个但是因为我太兴奋了所以我直接带上OMG黑色齐刘海对不起家人们没办法给你们放照片了,害怕辣眼睛因为辣眼睛,我直接就是反手一个祸害朋友最近比较熟的,chancelong(为什么熟,因为天天抄他作业,cbr假期里好像死了......
  • 2024-02-20 闲话
    今天学习了\(\displaystyle\int_{-\infty}^{+\infty}\exp(-x^2)dx\)的做法。然后把昨天说的题做掉了,不过有一个性质是\(a<0\)否则\(\exp(ax^2+bx+c)\)不能是概率密度函数。上午的大学物理实在是太难了,量纲学不会一点。于是去知乎上找了一个RAG的文章看,然后吸取经验......
  • 微控制器STM32L475RCT7[IC MCU 32BIT 256KB]、AZ5A25-01F.R7G瞬态抑制二极管(TVS),AONS
    1、微控制器STM32L475RCT7[ICMCU32BIT256KBFLASH64LQFP]STM32L475RC器件是基于高性能ARM®Cortex®-M432位RISC内核的超低功耗微控制器,工作频率高达80MHz。Cortex-M4内核具有浮点单元(FPU)单精度,支持所有ARM单精度数据处理指令和数据类型。它还实现了完整的DSP指令集和存储......
  • 2024年2月18日——KMP算法(未完成
    点击查看代码#include<bits/stdc++.h>usingnamespacestd;constintmaxn=1e6+10;intkmp[maxn];intla,lb,j;chara[maxn],b[maxn];intmain(){ cin>>a+1>>b+1; la=strlen(a+1),lb=strlen(b+1); for(inti=2;i<=lb;i++){ while(j&&b[j+1......
  • 初中英语优秀范文100篇-085How to Deal with Our Study Problems-如何处理我们的学习
    PDF格式公众号回复关键字:SHCZFW085记忆树1Althoughweoftenfeelstressed,weshouldfindsuitablewaystodealwithstress.翻译虽然我们经常感到有压力,但我们应该找到合适的方式来应对压力。简化记忆压力句子结构Althoughweoftenfeelstressed是一个让步......
  • 面试题随手记-2月20日
    异常/Exception类型原理java异常的层次结构图: throwable分为Error、Exception·Error  ·JVM内部问题,比如资源不足等,无法恢复·处理方式:不用处理·Exception·JVM通过处理可回到正常执行流程,即:可修复·分为uncheckedException(非受检异常)、checkedEx......
  • 解决方案 | 笔记本电脑能连上WIFI,但是无Internet显示地球图标,怎么回事?(win10)
    一、背景任务栏托盘区显示地球图标,但是实际上可以上网。   疑难诊断一般是这种情况: 二、可能的有效解决方案 0方案0:使用360断网急救箱傻瓜式修复个人制作|360断网急救箱新版-2.0版单文件绿色版分享(解决99%的电脑无法上网问题)https://www.cnblogs.com/issacne......
  • win10上安装nacos容器报端口被占用
    错误如下图排查过程1、检查8848端口是否被占用netstat-ano|findstr9091结论:没有2、经过google搜索Hyper-V会保留部分TCP端口,而windows上想要运行dockerdesktop,必须开启Hyper-V服务netshinterfaceipv4showexcludedportrangeprotocol=tcp命令查询结果,8848在排......
  • 2022 CCPC湖北省赛
    2022CCPC湖北省赛​ 这场打的怎么说,很难受。过年来与几个亲戚家的孩子见了面,被灌了不少白酒,没感觉什么酱香有啥好喝的,脑子倒是快成浆糊了。怒了,加训。题解里签到题的做法会写的简单点,这个[每日一棵splay](2022HubeiProvincialCollegiateProgrammingContest题解ABFJK......
  • 李宏毅《机器学习》总结 - 2022 HW8(Anomaly Detection、ResNet) Strong Baseline
    重新学习了一下ResNet。。这作业平均一跑就是3、4个小时题目大意是让你做异常检测(anomalydetection),即给你一些正常的图片,再让你测试图片是正常的还是异常的(可以理解为2分类问题,只不过其中一个类别是无限大的)代码:https://www.kaggle.com/code/skyrainwind/hw8-anomaly-detec......