文件 IO 操作

news2024/11/26 13:30:30

文章目录

    • 一 文件
      • 1.1 文本模式
      • 1.2 二进制模式
    • 二 函数
        • 2.1fopen()
        • 2.2 getc() 和 putc()
        • 2.3 fclose()
        • 2.4 fprintf() 和 fscanf()
        • 2.5 fgets() 和 fputs()
        • 2.6 rewind()
        • 2.7 fseek() 和 ftell()
        • 2.8 fflush()
        • 2.9 fgetpos() 和 fsetpos()
        • 2.10 feof() 和 ferror()
        • 2.11 ungetc()
        • 2.12 setvbuf()
        • 2.13 fread() 和 fwrite()

一 文件

C把文件看作是一系列连续的字节,每个字节都能被单独读取。C提供两种文件模式:文本模式 和 二进制模式。

1.1 文本模式

如果文件最初使用二进制编码的字符(例如:ASCLL 码 或 Unicode)表示文本(就像C字符串一样),该文件就是文本文件,其中包含文本内容。

  • 程序所见的内容和实际内容不同。
  • 读:把本地环境表示的行末尾或文件结尾映射成C模式(\r 转为 \n)
  • 写:(\n 转为 \r)

1.2 二进制模式

如果文件中的二进制值代表机器语言代码或数值数据(使用相同的内部表示,假设,用于 long 或 double 类型的值)或图片或音乐编码,改文件就是二进制文件,其中包含二进制内容。

  • 程序可以访问文件的每个字节
  • 若是写旧式 Mac 格式、MS-DOS格式或UNIX/Linux 格式的文件模式程序,应该用二进制模式,这样程序才能确定实际的文件内容并执行相应的动作。

二 函数

2.1fopen()

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

在这里插入图片描述

2.2 getc() 和 putc()

int getc(FILE *stream);
//fgetc(), getc() and getchar() return the character read as an unsigned char cast to an int or EOF on end of file or error.
//fgets() returns s on success, and NULL on error or when end of file occurs while no characters have been read.
//ungetc() returns c on success, or EOF on error.

int putc(int c, FILE *stream);
//fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on error.
//puts() and fputs() return a nonnegative number on success, or EOF on error.

与getchar() 和 putchar() 类似,不过要告诉getc() 和 putc() 函数使用哪一个文件。
例:将文件A 中的数据放在文件B中

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

int main(int argc,char* argv[])
{
    char ch;
    FILE* fp1;
    FILE* fp2;

    if(argc != 3)
    {
        printf("参数错误\n");
        return 0;
    }

    fp1 = fopen(argv[1],"r");
    fp2 = fopen(argv[2],"w");

    while( (ch = getc(fp1)) != EOF)
    {
        putc(ch,fp2);
    }

    fclose(fp1);
    fclose(fp2);


    return 0;
}

例子二:简单的文件压缩,保留每三个字符中的第一个

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

#define LEN 40

int main(int argc,char* argv[])
{
    FILE* in;
    FILE* out;

    int ch;
    char name[LEN];
    int count = 0;

    if(argc < 2)
    {
        fprintf(stderr,"Usage: %s filename\n",argv[0]);
        exit(EXIT_FAILURE);
    }

    //设置输入
    if( (in = fopen(argv[1],"r")) == NULL)
    {
        fprintf(stderr,"i coulun't open thr file \"%s\"\n",argv[1]);
        exit(EXIT_FAILURE);
    }

    //设置输出
    strncpy(name,argv[2],LEN-5);
    name[LEN-5] = '\0';
    strcat(name,".red"); //在文件名后添加 .red后缀
    if( (out = fopen(name,"w")) == NULL)
    {
        fprintf(stderr,"can't careate output file.\n");
        exit(3);
    }

    //拷贝数据
    while( (ch = getc(in)) != EOF)
    {
        if(count++ % 3 == 0)
        {
            putc(ch,out);
        }
    }

    if(fclose(in)!=0 || fclose(out)!=0)
    {
        fprintf(stderr,"Error incloseing files\n");
    }


    return 0;
}
//拷贝函数:
char *strncpy(char *dest, const char *src, size_t n);

//尾部添加字符strcat
char *strncat(char *dest, const char *src, size_t n);

fprintf()和printf() 类似,fprintf() 的第1个参数必须是一个文件指针。程序中的stderr指针把错误消息发至标准错误,C标准通常这么做。

2.3 fclose()

int fclose(FILE *stream);
//Upon successful completion, 0 is returned.  Otherwise, EOF is returned and errno is set to indicate the error.  In either case,  
//any  fur‐ther access (including another call to fclose()) to the stream results in undefined behavior.
//即成功返回0

fclose(fp)函数关闭fp指向的文件,必要时刷新缓冲区。对于比较正式的程序,应该检查是否关闭成功。如果关闭成功,返回0,否则返回EOF。
注:磁盘满、移动硬盘被移出或出现I/O错误,都会导致fclose()函数失败

2.4 fprintf() 和 fscanf()

fprintf()和printf() 类似,fscanf() 和 scanf()类似。区别在于第一个参数指定待处理的文件,fprintf() 的第1个参数必须是一个文件指针。程序中的stderr指针把错误消息发至标准错误,C标准通常这么做。

int fprintf(FILE *stream, const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);

例子:

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

#define LEN 41

int main(int argc,char* argv[])
{
    FILE* fp;
    char words[LEN];

    if( (fp = fopen("wordy","a+")) == NULL)
    {
        fprintf(stdout,"can't open file\n");
        exit(EXIT_FAILURE);
    }

    puts("enter words to add to the file;press the #");
    puts("key at the beginning of a line to terminate.");
    while( (fscanf(stdin,"%40s",words) == 1) && (words[0] != '#'))
    {
        fprintf(fp,"%s\n",words);
    }

    puts("File contenets:");
    rewind(fp);
    while(fscanf(fp,"%s",words) == 1)
    {
        puts(words);
    }

    puts("Dones");
    if(fclose(fp) != 0)
    {
        fprintf(stderr,"close file failed\n");
    }

    return 0;
}

从标准输入获取单词,然后输出到另一个文件
将 fscanf()第一个参数改为文件描述符,既可从文件读入

 rewind(fp); //rewind接收一个文件指针作为参数,移动到文件开始处。

在这里插入图片描述

2.5 fgets() 和 fputs()

第一个参数,fgets也和gets函数一样,也是表示存储输入位置的地址(char*类型)。
第二个参数是一个整数,代表待输入字符串的大小。
最后一个参数是一个文件指针,指定待读取的文件。
用法:fgets(buf,STLEN,fp);

fgets()函数读取输入直到第一个换行符后面,或者读到文件末尾,或者读取 STLEN-1 个字符,然后fgets() 在末尾添加一个空字符使之成为一个字符串。字符串大小其实是字符数加上一个空字符。

若fgets()在读到字符上线之前已读完一整行,它会吧表示行结尾的换行符放在空字符前面,。
fgets()函数在遇到EOF时将返回NULL值,可以利用这一机制检查是否到达文件末尾。

fputs() 接受两个参数,第一个是字符串的地址,第二个是文件指针。该函数根据传入地址找到的字符串写入指定的文件中。和puts()函数不通,fputs()在打印字符串时不会在其末尾添加换行符。

fput(buf,fp);

char *fgets(char *s, int size, FILE *stream);
int fputs(const char *s, FILE *stream);

2.6 rewind()

void rewind(FILE *stream);

返回到文件开始位置

2.7 fseek() 和 ftell()

Fseek 可把文件当做数据,在fopen()打开的文件中直接移动到任意字节处。
ftell()函数返回一个long类型的值,标识文件当前位置。

int fseek(FILE *stream, long offset, int whence);
//If whence is set to SEEK_SET, SEEK_CUR, or SEEK_END, the  offset  isrelative  to  the start of the file, the current position indicator, or end-of-file, respectively

long ftell(FILE *stream);
//返回值类型为long,返回的是参数指向的文件的当前位置距文件开始处的字节数;

fseek,第三个参数 whence 若是选择为 SEEK_SET,SEEK_CUR,SEEK_END,可以将文件指针偏移到文件开始,当前位置,文件末尾等位置。

例子:文件内容逆向打印

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

#define CNTL_Z '\032'

#define SLEN 81

int main(int argc,char* argv[])
{
    char file[SLEN];
    char ch;
    FILE* fp;
    long count,last;

    puts("enter the name of the file to be processed:");
    scanf("%s",file);

    if( (fp = fopen(file,"rb")) == NULL)
    {
        printf("reverse can't open %s\n",file);
        exit(EXIT_FAILURE);
    }

    fseek(fp,0L,SEEK_END); //定位到文件末尾

    last = ftell(fp);
    for(count  = 1L;count <= last; count++)
    {
        fseek(fp,-count,SEEK_END);  //回退
        ch = getc(fp);
        if(ch != CNTL_Z && ch != '\r')
        {
            putchar(ch);
        }
    }

    putchar('\n');
    
    fclose(fp);

    return 0;
}

fseek(fp,0L,SEEK_SET); //文件开始处
fseek(fp,10L,SEEK_SET); //文件中第10个字节
fseek(fp,2L,SEEK_CUR); //从当前位置往前移两个字节
fseek(fp,0L,SEEK_end); //定位到文件末尾
fseek(fp,-10L,SEEK_end);//从文件末尾回退10个字节

若是一切正常,fseek()返回0;如果出现错误(如试图移动的距离超过文件的范围),返回 -1

2.8 fflush()

调用fflush() 函数引起输出缓冲区中所有的未写入数据被发送到fp指定的输出文件。
这个过程称为刷新缓冲区。如果fp是空指针,所有输出缓冲区都会被刷新。在输入流中使用fflush()函数的效果是未定义的。只要最近一次操作不是输入操作,就可以用该函数来更新流(任何读写模式)

int fflush(FILE *stream)

2.9 fgetpos() 和 fsetpos()

fseek() 和 ftell() 潜在的问题是:他们都把文件大小限制在long类型能表示的范围内。

随着存储设备容量迅猛增长,文件也越来越大。
鉴于此,ANSIC新增了两个处理较大文件的新定位函数:fgetpos() 和 fsetpof()

这两个函数不适用long类型表示位置,而是使用一种新的类型:fpos_t(file position type,文件定位类型)。fpos_t类型是不是基本类型。

fpos_t 类型的变量或数据对象可以在文件中指定一个位置,他不能是数组类型。除此之外,没有其他限制。

int fgetpos(FILE *stream, fpos_t *pos);
//把fpos_t类型的值放在pos指向的位置上,该值描述了文件中的当前位置距文件开头的字节数。如果成功,fgetpos()函数返回0,如果失败返回非0;

int fsetpos(FILE *stream, const fpos_t *pos);
//使用pos指向位置上的fpos_t类型值来设置文件指针指向偏移该值后指定的位置。
成功返回0,失败返回非0.
fpot_t类型的值应该通过之前调用fgetpos获得

2.10 feof() 和 ferror()

int feof(FILE *stream);
int ferror(FILE *stream);

如果标准输入函数返回EOF,则通常表明函数已经到达文件末尾了。然而,出现错误读取时,函数也会返回EOF。

feof() 和 ferror() 函数用于区分两种情况。
当上一次输入调用检测到文件末尾时,feof() 返回一个非零值,否则返回0;
当读或写出现错误,ferror() 函数返回一个非零值,否则返回0;

2.11 ungetc()

int ungetc() 函数把C指定的字符放回输入流中,如果吧一个字符返回输入流,下次调用标准输入函数时将读取该字符。
例如:假设要读取下一个冒号前所有的字符,但是不包括冒号本身,可以使用getchar() 或 getc() 函数读取到冒号,然后使用ungetc() 把冒号放回输入流中。

ANSI C标准保证每次只会放回一个字符,如果实现允许把一行中的多个字符放回输入流,那么下次输入函数读入的字符顺序就会与放回去的顺序相反。

char *fgets(char *s, int size, FILE *stream);

2.12 setvbuf()

 int setvbuf(FILE *stream, char *buf, int mode, size_t size);

2.13 fread() 和 fwrite()

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
//返回成功读入项的数量。正常返回值就是nmemb,但如果出现写入错误,就会比nmenb小。

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
//返回成功写入项的数量。正常返回值就是nmemb,但如果出现写入错误,就会比nmenb小。

背景:之前用到的IO函数都是面向文本的,用于处理字符和字符串。如何在文件中存储数值?用fprintf() 函数 和 %f 转换说明只是把数据保存为字符串。
例如:

double num = 1.0/3;
fprintf(fp,"%f",num);
//fprintf(fp,"%.2f",num);
//fprintf(fp,"%.12f",num);

把num存储为8个字符,0.333333。使用%.2f说明将其存储为4个字符;使用%.12f说明把他存储为14个字符。

为了保证数值在存储前后一致,最精确的做法是使用与计算机相同的位组合来存储。因此,double类型的值就应该存在一个double大小的单元中。

如果以程序所用的表示法把数据存储在文件中,则称以二进制形式存储数据。

二进制和文本的用法很容易混淆。
可以用二进制模式打开文本格式的文件,可以把文本存储在二进制形式的文件中。可以调用getc()拷贝包含二进制数据的文件。然而,**一般而言,用二进制模式在二进制格式文件中存储二进制数据。**类似的,最常用的还是以文本格式打开文本文件中的文本数据。

  • size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
    fwrite()函数是把二进制数据写入文件。size_t是根据C类型定义的类型,是sizeof运算符返回的类型,通常是unsigned int.
    ptr 是待写入数据块的地址。
    size 表示待写入数据块的大小(以字节为单位)
    nmemb表示待写入数据块的数量。

例1:将一块256字节数据从buffer写入文件

char buf[256];
fwrite(buffer,256,1,fp);

例2:
保存一个内含10个double类型的数组

double earnings[10];
fwrite(earnings,sizeof(double),10,fp);

数据被分为10块,每块都是double的大小。

注:第一个类型不是固定类型,而是void*,

  • size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    接收参数与fwrite()一致.
    ptr是指待读取文件在内存中的地址
    fp指待读取的文件。
    该函数用于读取被fwrite()写入文件的数据。

例:恢复上例中保存的10个double类型的数据,可以这么做

double earnings[10];
fread(earnings,sizeof(double),10,fp);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/477752.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[python][vpython]用vpython实现小球砸弹簧代码

代码&#xff1a; from vpython import * # 加载vpython模块s1 canvas(width1200, height500, backgroundcolor.white, centervector(0, 1, 0)) # 定义画布 L0 1.4 # 定义初始高度 natural_length 0.9 # 设置弹簧原长 base_spring box(posvector(0, 0, 0), sizevector…

solidity 安全 如何阻止重入攻击

什么是可重入攻击&#xff1f; 我们使用合约的过程中&#xff0c;经常会遇到这种情况&#xff0c;智能合约能够调用外部的合约&#xff1b;这些外部合约又可以回调到调用他们的智能合约&#xff1b;在这种情况下&#xff0c;我们说智能合约被重新输入&#xff0c;这种情况被称为…

守护进程Daemon

进程组、对话期和控制终端关系 每个会话有且只有一个前台进程组&#xff0c;但会有0个或者多个后台进程组。产生在控制终端上的输入&#xff08;Input&#xff09;和信号&#xff08;Signal&#xff09;将发送给会话的前台进程组中的所有进程。对于输出&#xff08;Output&…

给大家介绍几个手机冷门但好用的小技巧

技巧一&#xff1a;拍照识别植物 手机的拍照识别植物功能是指在使用手机相机时&#xff0c;可以通过对植物进行拍照&#xff0c;并通过植物识别技术&#xff0c;获取植物的相关信息和资料。其主要优点如下&#xff1a; 方便实用&#xff1a;使用拍照识别植物功能&#xff0c;…

Small Tip: 怎么去Schedule一个Analysis for Office的workbook

workbook的query不能是本地的&#xff0c;也就是说不能是在包$Tmp里面的。这种的没办法在BO里面用SSO。也就没办法Schedule。 前提条件有&#xff1a; 1.BO和BW系统的SSO配置得OK。 如果没有SSO&#xff0c;那么每次打开workbook就会有一个要登录BW的弹窗&#xff0c;这样是…

从零开始学习Linux运维,成为IT领域翘楚(三)

文章目录 &#x1f525;Linux超级用户与伪用户&#x1f525;Linux文件基本属性&#x1f525;Linux权限字与权限操作 &#x1f525;Linux超级用户与伪用户 Linux下用户分为三类&#xff1a;超级用户、普通用户、伪用户 ⭐ 超级用户&#xff1a;用户名为root&#xff0c;具有一切…

初识 OPC

为什么需要OPC&#xff1f; 随着自动化的发展&#xff0c;工厂的自动化程度越来越高&#xff0c;面临着问题&#xff1a; 设备之间&#xff0c;设备与应用程序之间交互数据 不同产商设备/应用程序具有不同接口/通信协议&#xff0c;如何简单快速连接&#xff1f;采集的数据及…

【计算机网络】学习笔记:第四章 网络层【王道考研】更新中....

基于本人观看学习b站王道计算机网络课程所做的笔记&#xff0c;不做任何获利 仅进行交流分享 特此鸣谢王道考研 若有侵权请联系&#xff0c;立删 如果本篇笔记帮助到了你&#xff0c;还请点赞 关注 支持一下 ♡>&#x16966;<)!! 主页专栏有更多&#xff0c;如有疑问欢迎…

计算机组成原理4.2.2汉明码

编码的最小距离 奇校验和偶校验 看1的个数是奇数 还是偶数 汉明码 汉明码的配置 根据不等式&#xff0c;确定增添几位&#xff0c;根据指数放置增添位 汉明码的检错 分不同检测小组 分组规则&#xff1a;哪位为’1‘就是哪组元素。 1号位为‘1’的都是第一组元素&#…

JUnit 5 使用教程 及 JUnit 4/5的差异

1. JUnit 5产生的原因 JDK 8在java中带来了迷人的功能,最值得注意的是lambda表达式 为了适应 Java 8 风格的编码和新的功能特性,JUnit 提供了JUnit 5 2. JUnit 5 架构 与 JUnit 4 相比,JUnit 5 由来自三个不同子项目的几个不同模块组成:JUnit 5 = JUnit Platform + JUni…

controlnet1.1模型和预处理器功能详解(各预处理器出稿对比及对应模型说明)

ControlNet 1.1 与 ControlNet 1.0 具有完全相同的体系结构,ControlNet 1.1 包括所有以前的模型&#xff0c;具有改进的稳健性和结果质量&#xff0c;且增加并细化了多个模型。 命名规范 项目名版本号标识基础模型版本功能名文件后缀名 control 官方总是以control为项目名&…

Java NIO(Java Non-Blocking IO:非阻塞式IO)(2)

1.NIO非阻塞网络编程原理分析 1>.NIO非阻塞网络编程相关的(Selector、SelectionKey、ServerScoketChannel和SocketChannel)关系梳理图: 说明: ①.当客户端连接时,会通过服务器端ServerSocketChannel得到/生成对应的SocketChannel; ②.通过register(Selector sel,int ops)…

SpringBoot 如何防御 CSRF 攻击

SpringBoot 如何防御 CSRF 攻击 CSRF 原理CSRF实践CSRF防御前后端不分离方案前后端分离方案 CSRF 就是跨域请求伪造&#xff0c;英文全称是 Cross Site Request Forgery。 这是一种非常常见的Web攻击方式&#xff0c;其实是很好防御的&#xff0c;但是由于经常被很多开发者忽略…

压缩HTML引用字体

内容简介 有些网站为了凸显某部分字体&#xff0c;而引入自定义字体&#xff0c;但由于自定义字体相对都比较大&#xff08;几M&#xff09;,导致页面加载缓慢&#xff1b;所以本文介绍三种压缩字体的方法&#xff0c;可根据项目情况自行选择。 压缩方法 1、利用Fontmin程序&a…

ETL工具 - Kettle 输入输出算子介绍

一、Kettle 输入输出算子介绍 上篇文章对 Kettle 进行了简单的介绍及做了个简单的案例&#xff0c;但是对 Kettle 的Step算子工具没有做过多的解释&#xff0c;本篇文章从输入输出算子工具开始进行介绍。 下面是上篇文章的地址&#xff1a; ETL工具 - Kettle 介绍及基本使用 …

正点原直流有刷驱动板的硬件解说

这里写目录标题 H桥电流采集电路电源电压采集电路温度采集电路过流检测电路过流保护电路![请添加图片描述](https://img-blog.csdnimg.cn/fa130e17e23b471e8e27ae942e1ff125.png) H桥 因为光耦(EL0631)作用&#xff0c;PWM 引脚电平输入IN相反。 然后半桥芯片的逻辑表为&#x…

【Python】BeautifulSoup

一、什么是BeautifulSoup Beautiful Soup 简称 BS4&#xff08;其中 4 表示版本号&#xff09;是一个 Python 第三方库&#xff0c;它可以从 HTML 或 XML 文档中快速地提取指定的数据。 二、BS4下载安装 点击最下面的终端进如命令行界面 &#xff08;进入成功界面&#xff1a;&…

C++/Qt 小知识记录3

工作中遇到的一些小问题&#xff0c;总结的小知识记录&#xff1a;C/Qt 小知识 QLineEdit限制输入大于0的正整数QLayout内清空已布局的WidgetWindows结束进程直接结束&#xff0c;子进程不响应结束事件正常结束&#xff0c;子进程响应结束事件 CMake关闭控制台Console实体与值对…

【网络编程】网络基础知识总结

文章目录 一、局域网与广域网二、协议2.1 协议的概念2.2 协议分层2.3 数据传输的条件 三、OSI七层模型四、TCP/IP五层&#xff08;四层&#xff09;模型五、网络传输5.1 预备知识——报头5.2 局域网通信原理5.3 以太网和令牌环网5.3 网络传输流程图5.3.1 同一网段的两台计算机的…

海岛旅行回忆总结(不定更)

文章目录 概述大辣甲岛外伶仃岛、东澳岛长洲、南丫岛下川岛 概述 喜欢大海&#xff0c;与海滩相比&#xff0c;海岛的空气更好、海水更靓、人更少、污染更少 海岛位置日期天气小结大辣甲岛惠州2017年7月29~30日台风前夕&#xff0c;云淡风轻&#xff0c;阳光猛烈开发程度低&…