首页 > 其他分享 >10.C语言文件操作

10.C语言文件操作

时间:2023-02-09 23:55:31浏览次数:55  
标签:fp 10 stream 文件 int C语言 char FILE

10.2文件的打开和关闭

10.2.1 文件指针

在C语言中用一个指针变量指向一个文件,这个指针称为文件指针。

typedef struct
{
    short           level;	//缓冲区"满"或者"空"的程度 
    unsigned        flags;	//文件状态标志 
    char            fd;		//文件描述符
    unsigned char   hold;	//如无缓冲区不读取字符
    short           bsize;	//缓冲区的大小
    unsigned char   *buffer;//数据缓冲区的位置 
    unsigned        ar;	 //指针,当前的指向 
    unsigned        istemp;	//临时文件,指示器
    short           token;	//用于有效性的检查
}FILE;

FILE是系统使用typedef定义出来的有关文件信息的一种结构体类型,结构中含有文件名、文件状态和文件当前位置等信息。

声明FILE结构体类型的信息包含在头文件“stdio.h”中,一般设置一个指向FILE类型变量的指针变量,然后通过它来引用这些FILE类型变量。通过文件指针就可对它所指的文件进行各种操作。

C语言中有三个特殊的文件指针由系统默认打开,用户无需定义即可直接使用:

  • stdin: 标准输入,默认为当前终端(键盘),我们使用的scanf、getchar函数默认从此终端获得数据。
  • stdout:标准输出,默认为当前终端(屏幕),我们使用的printf、puts函数默认输出信息到此终端。
  • stderr:标准出错,默认为当前终端(屏幕),我们使用的perror函数默认输出信息到此终端。

文件指针
image

10.2.2 文件的打开

任何文件使用之前必须打开:

#include <stdio.h>
FILE * fopen(const char * filename, const char * mode);
功能:打开文件
参数:
	filename:需要打开的文件名,根据需要加上路径
	mode:打开文件的模式设置
返回值:
	成功:文件指针
	失败:NULL

第一个参数的几种形式:

FILE *fp_passwd = NULL;

	//相对路径:
	//打开当前目录passdw文件:源文件(源程序)所在目录
	FILE *fp_passwd = fopen("passwd.txt", "r");
	
	//打开当前目录(test)下passwd.txt文件
	fp_passwd = fopen(". / test / passwd.txt", "r");
	
	//打开当前目录上一级目录(相对当前目录)passwd.txt文件
	fp_passwd = fopen(".. / passwd.txt", "r");
		
	//绝对路径:
	//打开C盘test目录下一个叫passwd.txt文件
	fp_passwd = fopen("c:/test/passwd.txt","r");

第二个参数的几种形式(打开文件的方式):

打开模式
含义

  • r或rb:以只读方式打开一个文本文件(不创建文件,若文件不存在则报错)
  • w或wb:以写方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)
  • a或ab:以追加方式打开文件,在末尾添加内容,若文件不存在则创建文件
  • r+或rb+:以可读、可写的方式打开文件(不创建新文件)
  • w+或wb+:以可读、可写的方式打开文件(如果文件存在则清空文件,文件不存在则创建一个文件)

注意:

  • b是二进制模式的意思,b只是在Windows有效,在Linux用r和rb的结果是一样的
  • Unix和Linux下所有的文本文件行都是\n结尾,而Windows所有的文本文件行都是\r\n结尾
  • 在Windows平台下,以“文本”方式打开文件,不加b:
    • 当读取文件的时候,系统会将所有的 "\r\n" 转换成 "\n"
    • 当写入文件的时候,系统会将 "\n" 转换成 "\r\n" 写入
    • 以"二进制"方式打开文件,则读写都不会进行这样的转换
    • 在Unix/Linux平台下,“文本”与“二进制”模式没有区别,"\r\n" 作为两个字符原样输入输出
  • 注意:  打开的选项只有带r的选项,如果文件不存在,则不创建文件
    带w选项的,打开时会清空文件
    fopen的返回值:  如果成功返回FILE结构体地址,失败返回NULL
    返回的文件流指针标识了打开的那个文件
int main(void)
{
	FILE *fp = NULL;
	// "\\"这样的路径形式,只能在windows使用
	// "/"这样的路径形式,windows和linux平台下都可用,建议使用这种
	// 路径可以是相对路径,也可是绝对路径
	fp = fopen("../test", "w");
	//fp = fopen("..\\test", "w");

	if (fp == NULL) //返回空,说明打开失败
	{
		//perror()是标准出错打印函数,能打印调用库函数出错原因
		perror("open");
		return -1;
	}
	return 0;
}

10.2.3 文件的关闭

任何文件在使用后应该关闭:

  • 打开的文件会占用内存资源,如果总是打开不关闭,会消耗很多内存
  • 一个进程同时打开的文件数是有限制的,超过最大同时打开文件数,再次调用fopen打开文件会失败
  • 如果没有明确的调用fclose关闭打开的文件,那么程序在退出的时候,操作系统会统一关闭。
#include <stdio.h>
int fclose(FILE * stream);
功能:关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。
参数:
	stream:文件指针
返回值:
	成功:0
	失败:-1

	FILE * fp = NULL;
	fp = fopen("abc.txt", "r");
	fclose(fp);
  • 5 vs中. 当前./相对路径问题:

    • 1 如果直接在vs中调试运行: 相对路径相对的是工程文件

      image

    • 2 如果手动运行,.exe文件.相对路径相对的是可执行文件
      image

6 设备文件

  • stdin
  • stdout
  • stderr
    image

10.3文件的顺序读写

10.3.1 fputc()

1)写文件

#include <stdio.h>
int fputc(int ch, FILE * stream);
功能:将ch转换为unsigned char后写入stream指定的文件中
参数:
	ch:需要写入文件的字符
	stream:文件指针
返回值:
	成功:成功写入文件的字符
	失败:返回-1
char buf[] = "this is a test for fputc";
int i = 0;
int n = strlen(buf);
for (i = 0; i < n; i++)
{
	//往文件fp写入字符buf[i]
	int ch = fputc(buf[i], fp);
	printf("ch = %c\n", ch);
}

2)文件结尾

在C语言中,EOF表示文件结束符(end of file)。在while循环中以EOF作为文件结束标志,这种以EOF作为文件结束标志的文件,必须是文本文件。在文本文件中,数据都是以字符的ASCII代码值的形式存放。我们知道,ASCII代码值的范围是0~127,不可能出现-1,因此可以用EOF作为文件结束标志。

#define EOF     (-1)

当把数据以二进制形式存放到文件中时,就会有-1值的出现,因此不能采用EOF作为二进制文件的结束标志。为解决这一个问题,ANSI C提供一个feof函数,用来判断文件是否结束。feof函数既可用以判断二进制文件又可用以判断文本文件。

#include <stdio.h>
int feof(FILE * stream);
功能:检测是否读取到了文件结尾。判断的是最后一次“读操作的内容”,不是当前位置内容(上一个内容)。
参数:
	stream:文件指针
返回值:
	非0值:已经到文件结尾
	0:没有到文件结尾

image

10.3.2 fgetc()

### 3)读文件
#include <stdio.h>
int fgetc(FILE * stream);
功能:从stream指定的文件中读取一个字符
参数:
	stream:文件指针
返回值:
	成功:返回读取到的字符
	失败:-1

char ch;
#if 0
while ((ch = fgetc(fp)) != EOF)
{
	printf("%c", ch);
}
printf("\n");
#endif

while (!feof(fp)) //文件没有结束,则执行循环
{
	ch = fgetc(fp);
	printf("%c", ch);
}
printf("\n");

强化训练:实现vi、cat命令
image
image

10.3.2按照行读写文件fgets、fputs

10.3.3 fputs()

1)写文件
#include <stdio.h>
int fputs(const char * str, FILE * stream);
功能:将str所指定的字符串写入到stream指定的文件中,字符串结束符 '\0'  不写入文件。 
参数:
	str:字符串
	stream:文件指针
返回值:
	成功:0
	失败:-1

char *buf[] = { "123456\n", "bbbbbbbbbb\n", "ccccccccccc\n" };
int i = 0;
int n = 3;
for (i = 0; i < n; i++)
{
	int len = fputs(buf[i], fp);
	printf("len = %d\n", len);
}

10.3.4 fgets()

#include <stdio.h>
char * fgets(char * str, int size, FILE * stream);
功能:从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 '\0' 作为字符串结束。
参数:
	str:字符串
	size:指定最大读取字符串的长度(size - 1)
	stream:文件指针
返回值:
	成功:成功读取的字符串
	读到文件尾或出错: NULL

char buf[100] = 0;

while (!feof(fp)) //文件没有结束
{
	memset(buf, 0, sizeof(buf));
	char *p = fgets(buf, sizeof(buf), fp);
	if (p != NULL)
	{
		printf("buf = %s", buf);
	}
}

3)强化训练:文件版四则运算
有个文件大小不确定,每行内容都是一个四则运算表达式,还没有算出结果,写一个程序,自动算出其结果后修改文件。
image

10.3.3按照格式化文件fprintf、fscanf

10.3.5 fprintf()

1)写文件
#include <stdio.h>
int fprintf(FILE * stream, const char * format, ...);
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0'  为止。
参数:
	stream:已经打开的文件
	format:字符串格式,用法和printf()一样
返回值:
	成功:实际写入文件的字符个数
	失败:-1

fprintf(fp, "%d %d %d\n", 1, 2, 3);

image

10.3.6 fscanf()

读文件
#include <stdio.h>
int fscanf(FILE * stream, const char * format, ...);
功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
参数:
	stream:已经打开的文件
	format:字符串格式,用法和scanf()一样
返回值:
	成功:参数数目,成功转换的值的个数
	失败: - 1

int a = 0;
int b = 0;
int c = 0;
fscanf(fp, "%d %d %d\n", &a, &b, &c);
printf("a = %d, b = %d, c = %d\n", a, b, c);

image
强化训练:文件版排序
image

10.3.4按照块读写文件fread、fwrite

10.3.7 fwrite()

1)写文件
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式给文件写入内容
参数:
	ptr:准备写入文件数据的地址
	size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小
	nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb
	stream:已经打开的文件指针
返回值:
	成功:实际成功写入文件数据的块数目,此值和 nmemb 相等
	失败:0


typedef struct Stu
{
	char name[50];
	int id;
}Stu;

Stu s[3];
int i = 0;
for (i = 0; i < 3; i++)
{
	sprintf(s[i].name, "stu%d%d%d", i, i, i);
	s[i].id = i + 1;
}

int ret = fwrite(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);

image

10.3.8 fread()

2)读文件
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式从文件中读取内容
参数:
	ptr:存放读取出来数据的内存空间
	size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小
	nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb
	stream:已经打开的文件指针
返回值:
	成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。
	失败:0

typedef struct Stu
{
	char name[50];
	int id;
}Stu;

Stu s[3];
int ret = fread(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);

int i = 0;
for (i = 0; i < 3; i++)
{
	printf("s = %s, %d\n", s[i].name, s[i].id);
}

image

10.4 文件的随机读写

fseek

#include <stdio.h>
long ftell(FILE *stream);
功能:获取文件流(文件光标)的读写位置。
参数:
	stream:已经打开的文件指针
返回值:
	成功:当前文件流(文件光标)的读写位置
	失败:-1

image

rewind

#include <stdio.h>
void rewind(FILE *stream);
功能:把文件流(文件光标)的读写位置移动到文件开头。
参数:
	stream:已经打开的文件指针
返回值:
	无返回值

typedef struct Stu
{
	char name[50];
	int id;
}Stu;

//假如已经往文件写入3个结构体
//fwrite(s, sizeof(Stu), 3, fp);

Stu s[3];
Stu tmp; 
int ret = 0;

//文件光标读写位置从开头往右移动2个结构体的位置
fseek(fp, 2 * sizeof(Stu), SEEK_SET);

//读第3个结构体
ret = fread(&tmp, sizeof(Stu), 1, fp);
if (ret == 1)
{
	printf("[tmp]%s, %d\n", tmp.name, tmp.id);
}

//把文件光标移动到文件开头
//fseek(fp, 0, SEEK_SET);
rewind(fp);

ret = fread(s, sizeof(Stu), 3, fp);
printf("ret = %d\n", ret);

int i = 0;
for (i = 0; i < 3; i++)
{
	printf("s === %s, %d\n", s[i].name, s[i].id);
}

ftell

image

标签:fp,10,stream,文件,int,C语言,char,FILE
From: https://www.cnblogs.com/Epiephany/p/17107526.html

相关文章

  • win10 扩展c盘 “PARTITION_BASIC_DATA_GUID"
    一不小心化身为c盘战士了,系统卡到不行于是通过pe登入系统,然后下载傲梅分区助手(嘎嘎好用)傲梅官网https://www.disktool.cn/download.html傲梅分区助手使用教程https://......
  • 预处理指令详解(C语言
    一、预处理符号预处理符号是C语言内置的符号,是可以直接使用的。其中,若遵顼ANSIC,则__STDC__为1,否则未定义。二、#define1)定义标识符define可以用来定义标识符,其语法......
  • C语言--void
    C语言中存在空类型(void),这种类型表示“空”void时基础类型,不是基础数据类型,不能定义变量void可用于函数参数,表示函数无参数void可用于函数返回类型,表示函数无返回值C语......
  • C语言--函数参数深度剖析
    函数定义时参数没有具体值,函数调用时指定参数初始值函数参数在函数内部等同于普通变量在C语言中,数组作为函数参数传递时,大小信息丢失在函数内部修改数组形参,将影响数组......
  • Linux文件常用操作命令
    一、Linux文件和目录简单操作1.1查看文件ls查看当前目录下的文件如:-a显示所有文件及目录(ls内定将文件名或目录名称开头为"."的视为隐藏档,不会列出)-l除文件名称......
  • 《剑指Offer》-32-从上到下打印二叉树/力扣-102/力扣-103
    就是二叉树的层序遍历,我记得这题,用栈用队列,然后有个关键的size()Ⅰ vector<int>levelOrder(TreeNode*root){ vector<int>res; if(!root)returnres; queue<T......
  • C语言--深入浅出函数调用
    1.main()是应用程序与操作系统的一个“约定”;当操作系统运行应用程序时,首先调用的就是main()函数;应用程序必须运行于操作系统,接受操作系统管理2.应用程序的运行3.深......
  • 问题解决:由于找不到msvcr110.dll,无法继续执行代码
    报错解决下载地址:https://www.microsoft.com/zh-cn/download/details.aspx?id=30679......
  • Java FileInputStream/FileOutputStream的应用 文件读取和写入//京鸿通信科技//www.ky
    这是一对继承于InputStream和OutputStream的类,用于本地文件读写(二进制格式读写并且是顺序读写,读和写要分别创建出不同的文件流对象);本地文件读写编程的基本过程为:① 生......
  • //京鸿通信科技//www.kyohoon.com//java文件一行一行读取_java一行一行写入或读取文件
    参考地址:http://www.cnblogs.com/linjiqin/archive/2011/03/23/1992250.htmljava中提供一行一行读取的类是BufferedReader,其有一个readLine()方法。java中提供一行一......