文件的输出和读写 1.0

scanf_s的返回值

int main(void)
{
    int number;
    int result;
    
    puts("Enter an integer:");

    result = scanf_s("%d", &number);

    if (result == 1){
        printf("You entered thr integer: %d", number);
    }
    else if (result == EOF){
        // End of file -1
        //专门用来指示文件读取或输入操作已经到达了数据源的末尾
        printf("An error occurred or end of file was reached.\n");
        return 1;                    //直接退出函数
    }
    else{
        printf("Invalid input for integer.\n");
        return 1;
    }
    return 0;
}

result == 1说明读取得到的是数字,如果输入的是字符,会跳到最后一个else

流(Stream) 

FILE* stream这种定义方式,包含了各种各样的流·

1.文件流

        磁盘

        用于读取与写入在磁盘上的文件

2.标准I/O流

        stdin: 默认连接到键盘,用于程序输入 -> scanf_s

        stdout: 默认连接到控制台或者是屏幕,用于程序输出 -> printf

        stderr: 默认也连接到控制台或者屏幕, 专门输出错误信息和警告, 使得其能够被区分开来或者是重定向到不同的目的地

3.管道流

        用于进程之间的通信(IPC), 允许一个进程的输出成为另一个进程的输入。plpen();

4.内存流

        允许你将流与内存缓冲区相关联,使得你可以向内存中读写数据,就像操作文件一样。POSIX -> fmemopen

5.网络流

        套接字(Sockets)

6.设备流

        特殊文件或者是设备打印机

小实例

#include 
#include 
#include 
#include 


int main(void)
{
	FILE* fileStream = NULL;

	char buffer[1023] = { 0 };

	//fopen()
	//fopen_s()

	//打开文件,设定文件路径要读取的文件,设定文件的操作模式
	errno_t err = fopen_s(&fileStream, "C:\\Users\\yangy\\Desktop\\Hello!.txt", "r");

	//这里对返回值进行处理,!= 0说明读取失败或者是读取的流是一个NULL
	if (err != 0 || fileStream == NULL) {
		//这是专门用来错误处理的函数,正确地反馈错误
		perror("Error opening file");
		return EXIT_FAILURE;
	}

	//需要对fopen进行处理,可能会出现文件路径不对,文件不存在,文件出现了异常,文件没有权限访问

	//令fgets != NULL即可一直读取下去
	while (fgets(buffer, sizeof(buffer), fileStream) != NULL) {
		printf("%s", buffer);
	}

	//之前用的字符串buffer此时里面是有东西的,之后我们不再使用了,就得确保他是空的,不然是一件非常不文明的事情
	memset(buffer, 0, sizeof(buffer));

	//如果需要读取两次的话,第一次读的文件末尾是没有换行符的,需要手动加
	printf("\n");

	//这个函数不管多长都能直接定位到文件开头
	rewind(fileStream);

	//也可以一个字符的读,一个字一个字往出蹦,不需要缓冲区但是比较慢
	int ch = 0;

	while ((ch = fgetc(fileStream)) != EOF) {
		putchar(ch);
	}

	//最后一定要关闭文件流,关闭也可能出现问题,需要对fclose进行处理
	if (fclose(fileStream) != 0) {
		perror("Error closing file");
		return EXIT_FAILURE;
	}

	return 0;
}

rewind和fseek的区别与联系

区别说明:

特性 rewind() fseek()
返回值 返回成功/失败状态
错误标志处理 会清除流的错误标志 不会修改错误标志
参数复杂度 无参数,直接回到开头 需要指定偏移量和起始点

最佳实践:

  • 如果只需要简单回到文件开头,推荐使用 rewind()

  • 如果需要更精确的控制或错误检查,使用 fseek(fp, 0L, SEEK_SET)

  • 使用后建议检查文件状态:

fseek的更多解释

示例 1:移动到文件开头

FILE *fp = fopen("data.txt", "r");
if (fp == NULL) {
    perror("文件打开失败");
    exit(EXIT_FAILURE);
}
// 将指针移动到文件开头(等价于 rewind(fp))
fseek(fp, 0L, SEEK_SET);

示例 2:跳过前 N 字节

// 跳过前 100 字节(从开头向后移动)
fseek(fp, 100L, SEEK_SET);
// 读取后续内容
char buffer[1024];
fread(buffer, sizeof(char), 1024, fp);

示例 3:从当前位置移动

// 假设当前指针在位置 200
// 向后移动 50 字节(正偏移)
fseek(fp, 50L, SEEK_CUR); // 新位置 = 250

// 向前移动 30 字节(负偏移)
fseek(fp, -30L, SEEK_CUR); // 新位置 = 220

示例 4:移动到文件末尾

// 移动到文件末尾
fseek(fp, 0L, SEEK_END); // 用于追加数据或计算文件大小

// 在末尾追加数据
fputs("追加的内容", fp);

示例 5:读取倒数第 N 字节

// 读取文件的最后 10 字节
fseek(fp, -10L, SEEK_END); // 从末尾向前移动 10 字节
char last10[11];
fread(last10, sizeof(char), 10, fp);
last10[10] = '\0'; // 添加字符串结束符
printf("最后10字节: %s\n", last10);

示例 6:修改文件中间内容

// 修改文件中第 50 字节处的内容(二进制文件)
FILE *fp = fopen("data.bin", "r+"); // 读写模式
if (fp == NULL) exit(EXIT_FAILURE);

fseek(fp, 49L, SEEK_SET); // 移动到第 50 字节(索引从 0 开始)
fputc('X', fp); // 修改该字节
fclose(fp);

示例 7:动态计算文件大小

FILE *fp = fopen("data.bin", "rb");
if (fp == NULL) exit(EXIT_FAILURE);

fseek(fp, 0L, SEEK_END); // 移动到文件末尾
long file_size = ftell(fp); // 获取文件大小(字节数)
rewind(fp); // 回到开头

printf("文件大小: %ld 字节\n", file_size);

示例 8:复杂偏移组合

// 假设文件指针初始位置为 100
fseek(fp, 100L, SEEK_SET);

// 从当前位置向前移动 50 字节
fseek(fp, 50L, SEEK_CUR); // 新位置 = 150

// 从文件末尾向前移动 200 字节
fseek(fp, -200L, SEEK_END); // 适用于大文件末尾操作

错误处理

// 假设文件指针初始位置为 100
fseek(fp, 100L, SEEK_SET);

// 从当前位置向前移动 50 字节
fseek(fp, 50L, SEEK_CUR); // 新位置 = 150

// 从文件末尾向前移动 200 字节
fseek(fp, -200L, SEEK_END); // 适用于大文件末尾操作

注意事项

  1. 二进制文件 vs 文本文件
    在文本文件中,某些系统(如 Windows)的换行符 \r\n 可能被转换为 \n,导致 fseek 偏移量与实际字节数不一致。建议对文本文件谨慎使用偏移量。

  2. 有效性检查
    使用 ftell() 可获取当前位置:

    long pos = ftell(fp);
    if (pos == -1L) {
        perror("ftell 失败");
    }
  3. 重置文件状态
    fseek 可以清除文件结束标志(feof() 返回 false),但不会自动清除错误标志(需用 clearerr(fp))。

fopen_s的不同区别

基础模式

模式 描述 文件存在 文件不存在 文件指针位置 操作权限
r 只读 打开文件 报错 开头 只能读
w 只写 清空 创建文件 开头 只能写
a 追加 打开文件 创建文件 末尾 只能写

组合模式(读写模式)

模式 描述 文件存在 文件不存在 文件指针位置 操作权限
r+ 读写(更新模式) 打开文件 报错 开头 可读可写
w+ 读写(清空并创建) 清空 创建文件 开头 可读可写
a+ 读写(追加模式) 打开文件 创建文件 末尾 可读可写

  • a+ 模式下,写入总是追加到末尾,但读取可以定位到任意位置(需先调用 fseek 调整指针)

  • r+ 和 w+ 的主要区别:r+ 不删除原内容,w+ 会清空原内容


二进制模式

在模式后添加 b(如 rbwb+),用于处理二进制文件:

FILE *fp = fopen("data.bin", "rb"); // 二进制只读
  • 文本模式 vs 二进制模式

    • 文本模式:自动处理换行符(如 Windows 将 \r\n 转为 \n

    • 二进制模式:直接操作原始字节(无转换)

写入函数

fputc('O', fileStream);
fputs("dashdasdjha", fileStream);

fprintf_s(fileStream, "asdhasdi%d %d %d sdhaskdh%d", 19, 29, 39, 1);

这里因为是写入,一定要与之前的fopen_s函数中的模式相匹配

ftell功能描述

long ftell(FILE *stream);
  • 作用:返回当前文件指针的位置(相对于文件开头的偏移量,单位:字节)

  • 返回值

    • 成功:返回 long 类型的当前位置

    • 失败:返回 -1L(需检查错误)

1. 获取文件大小
FILE *fp = fopen("data.bin", "rb");
if (fp == NULL) exit(EXIT_FAILURE);

fseek(fp, 0L, SEEK_END); // 移动到文件末尾
long file_size = ftell(fp); // 获取总字节数
printf("文件大小: %ld 字节\n", file_size);

rewind(fp); // 重置指针到文件开头
fclose(fp);
2. 记录当前位置
long original_pos = ftell(fp); // 保存当前位置
// 执行某些操作后...
fseek(fp, original_pos, SEEK_SET); // 返回原位置
3. 检查指针移动是否成功
if (fseek(fp, 100L, SEEK_SET) == 0) {
    printf("当前指针位置: %ld\n", ftell(fp)); // 应输出 100
} else {
    perror("指针移动失败");
}

注意事项

  1. 二进制文件 vs 文本文件

    • 二进制模式:ftell() 返回的偏移量精确对应物理字节位置

    • 文本模式:

      • Windows 系统中换行符 \r\n 会被转换为 \n,导致逻辑位置与物理位置不一致,这里\r算一个\n也算一个(算一个字节)

      • 建议文本文件操作时谨慎使用 ftell() 的返回值

  2. 文件有效性检查

    long pos = ftell(fp);
    if (pos == -1L) {
        perror("ftell 失败");
        // 常见错误原因:
        // - 文件未成功打开
        // - stream 参数无效
        // - 文件是终端设备(如 stdin/stdout)
    }

fscanf_s

与scanf的返回值一样,需要判断是否为1

char bufferplus[256] = { 0 };
int number = 0;
float FloatNumber = 0.0;
char character = 0;
//scanf_s的问题

if (fscanf_s(fileStream, "%d", &number) != 1) {
	printf("读取失败");
}

if (fscanf_s(fileStream, "%s", &bufferplus, (unsigned)sizeof(bufferplus)) != 1) {
	printf("读取失败");
}

if (fscanf_s(fileStream, "%f", &FloatNumber) != 1) {
	printf("读取失败");
}

if (fscanf_s(fileStream, " %c", &character, 1)
	!= 1) {
	printf("读取失败");
}

printf("%d\n", number);
printf("%f\n", FloatNumber);
printf("%c\n", character);
printf("%s\n", bufferplus);

scanf 在不同的格式化控制符下对空格的处理方式不同

想读取的东西得按顺序来

1. 使用 %s 读取字符串时

当使用 %s 格式化控制符时,scanf 不会读取空格、制表符(\t)和换行符(\n),它会将这些字符视为字符串的分隔符。一旦遇到这些空白字符,scanf 就会停止读取,并在字符串末尾自动添加字符串结束符 '\0'

示例代码

#include 

int main() {
    char str[100];
    printf("请输入一个包含空格的字符串:");
    scanf("%s", str);
    printf("你输入的字符串是:%s\n", str);
    return 0;
}

输入与输出示例

请输入一个包含空格的字符串:hello world
你输入的字符串是:hello

在这个例子中,当输入 hello world 时,scanf 遇到空格就停止读取,只将 hello 存储到 str 数组中。

2. 使用 %c 读取字符时

当使用 %c 格式化控制符时,scanf 会读取包括空格、制表符和换行符在内的任意字符。也就是说,空格对于 %c 来说就是一个普通的字符。

示例代码

#include 

int main() {
    char ch;
    printf("请输入一个字符(可以是空格):");
    scanf("%c", &ch);
    printf("你输入的字符是:%c\n", ch);
    return 0;
}

输入与输出示例

请输入一个字符(可以是空格):  
你输入的字符是: 

这里输入一个空格,scanf 会将这个空格字符读取并存储到 ch 变量中。

3. 使用其他格式控制符(如 %d%f 等)读取数值时

对于读取整数(%d)、浮点数(%f)等数值类型的格式控制符,scanf 会自动跳过前导的空白字符(空格、制表符、换行符),直到遇到有效的数字字符才开始读取。

示例代码

#include 

int main() {
    int num;
    printf("请输入一个整数(可以在前面加空格):");
    scanf("%d", &num);
    printf("你输入的整数是:%d\n", num);
    return 0;
}

输入与输出示例

请输入一个整数(可以在前面加空格):    123
你输入的整数是:123

fprintf

格式化往文件里打印

fprintf(file, "整数: %d\n", num);
fprintf(file, "浮点数: %.2f\n", f);
fprintf(file, "字符串: %s\n", str);

ferror feof clearerr

while (fgets(buffer, sizeof(buffer), file_ptr)!= NULL) {
        printf("%s", buffer);
    }

    if (ferror(file_ptr)) {
        perror("读取文件时候发生了错误!");
        clearerr(file_ptr);
    }

    if (feof(file_ptr)) {
        printf("已经到达文件的末尾...\n");
    } else {
        printf("文件未到达末尾,可能因为发生了错误!\n");
    }

ferror读取文件过程中检查是否发生错误

feof检查文件流是否达到的末尾

claererr清除错误

更专业一点的错误处理

抽离文件读取函数

void read_config_safe(const char* filename);

int main(void)
{
	const char* filename = "C:\\Users\\yangy\\Desktop\\Hello!.txt";

	read_config_safe(filename);

	return 0;
}

void read_config_safe(const char* filename) {

	FILE* fileStream = NULL;

	errno_t err = fopen_s(&fileStream, filename, "r+");

	//比较标准的错误处理
	if (err != 0 || fileStream == NULL) {
		char errorMsg[256] = { 0 };

		//这里把错误信息装到了这个数组里
		strerror_s(errorMsg, sizeof(errorMsg), errno);

		//这里的fprintf不再是将错误信息打印到文本里了,这里用stderr是将错误信息放到了cmd或者是用户的显示屏上,也有可能是一个设备专门去报错,这样写比较灵活
		fprintf(stderr, "Failed to open config file for reading : %s\n", errorMsg);

		exit(EXIT_FAILURE);
	}

}

 

写入文件用fprintf

确保关闭所有的流,这一步是为了保险

//All other files are closed
unsigned int numclosed = _fcloseall();
printf("Number if files closed by _flcloseall: %u", numclosed);

使用r+来修改日志,待修缮

#include 
#include 
#include 
#include 

#define BUFFER_SIZE 1024

errno_t update_log_replace_s(const char* logFile, const char* rearchStr, const char* replaceStr);

int main(void)
{
	const char* logFile = "C:\\Users\\yangy\\Desktop\\log.txt";

	const char* rearchStr = "Memory usage exceeds 80% of available memory.";

	const char* replaceStr = "[2023-02-13T12:36:00Z] [INFO] Memory usage is back to normal levels.";

	//更新需要返回值来告诉是否更新成功
	errno_t result = update_log_replace_s(logFile, rearchStr, replaceStr);

	if (result != 0) {
		char config_msg[256] = { 0 };

		strerror_s(config_msg, sizeof(config_msg), errno);

		fprintf(stderr, "An error occured: %s", config_msg);

		exit(EXIT_FAILURE);
	}
	else {
		printf("Record updated successfully");
	}
	_fcloseall();

	return 0;
}


//修改log日志中的一条警告
errno_t update_log_replace_s(const char* logFile, const char* rearchStr, const char* replaceStr) {
	//因为涉及到更新,要确保传进来的东西都不是空
	if (logFile == NULL || rearchStr == NULL || replaceStr == NULL) {
		return EINVAL;				//返回无效参数
	}

	FILE* fileStream = NULL;

	errno_t err = fopen_s(&fileStream, logFile, "r+");

	if (err != 0 || fileStream == NULL) {
		char config_msg[256] = { 0 };

		strerror_s(config_msg, sizeof(config_msg), errno);

		fprintf(stderr, "Error to open config file to r+: %s", config_msg);

		exit(EXIT_FAILURE);
	}

	char buffer[BUFFER_SIZE] = { 0 };
	long position = 0;
	int found = 0;

	while (fgets(buffer, sizeof(buffer), fileStream)) {
		//strstr去寻找是否有想要的字符串
		if (strstr(buffer, rearchStr) != NULL) {
			found = 1;			//标志着已经找到
			//这里得知要找的字符的具体位置
			//这个时候fileStream在我们要找的句子的末尾
            //这里加减1取决于是否是二进制
			position = ftell(fileStream) - (long)strlen(buffer);
			break;				//找到第一个匹配项之后立刻退出
		}
	}

	if (found) {
		//将文件流从目标句段的末尾定位到开头
		fseek(fileStream, position, SEEK_SET);

		//为了确保安全计算替换文本和目标文本的长度差异
		size_t replace_len = strlen(replaceStr);
		size_t research_len = strlen(rearchStr);

		if (replace_len > BUFFER_SIZE || research_len > BUFFER_SIZE) {
			fclose(fileStream);

			return ERANGE;				//返回错误码,表示字符串长度超出范围
		}

		//写入新纪录之前,删除原有行的数据,用空格去填充,防止删完了下一行加上来了
		memset(buffer, ' ', strlen(buffer) - 1);					//用空格填充保持文件大小不变,-1是防止换掉\n换行符

		buffer[strlen(buffer) - 1] = '\n';			//保留换行符

		fseek(fileStream, position, SEEK_SET);

		int result = fputs(replaceStr, fileStream);					//彻底清除原行的内容

		//确保清除成功
		if (result == EOF) {
			fclose(fileStream);
			return errno;
		}

		fseek(fileStream, position, SEEK_SET);		//再次回到文件的开头
	}
	else {
		fclose(fileStream);
		return ENOENT;					//返回未找到的匹配项
	}

	fclose(fileStream);

	return 0;
}

fgets 函数简介

fgets 函数的原型如下:

char *fgets(char *str, int num, FILE *stream);

该函数从指定的文件流 stream 中读取最多 num - 1 个字符,并将其存储到字符数组 str 中,直到遇到换行符 \n 或者文件结束符 EOF 为止。读取完成后,会在字符串末尾自动添加字符串结束符 '\0'

文件流指针的位置变化

  • 读取正常行内容时:假设文件中有一行内容为 "Hello, World!\n",当使用 fgets 读取这一行时,如果 num 足够大,fgets 会读取 "Hello, World!\n" 并存储到 str 中,然后文件流指针会移动到下一行的起始位置(如果存在下一行)。例如:
#include 

int main() {
    FILE *file = fopen("test.txt", "r");
    if (file == NULL) {
        perror("文件打开失败");
        return 1;
    }

    char buffer[100];
    fgets(buffer, sizeof(buffer), file);  // 读取一行内容
    // 此时文件流指针位于下一行的起始位置

    fclose(file);
    return 0;
}
  • 遇到换行符时:如果文件中的内容为 "Hello\nWorld",当使用 fgets 读取时,它会读取 "Hello\n" 并存储到 str 中,文件流指针会移动到 'W' 这个字符的位置,即下一行的起始字符处。
  • 读取部分内容时:如果 num 较小,不足以读取完整的一行内容,fgets 会读取 num - 1 个字符并存储到 str 中,文件流指针会停留在本次读取的最后一个字符的下一个位置。例如,文件内容为 "Hello, World!\n",而 num 为 5,那么 fgets 会读取 "Hell" 并存储到 str 中,文件流指针会停留在 'o' 这个字符的位置。

保存游戏设置简单代码(部分变量命名有误)

#include 
#include 
#include 

typedef enum{
	ESAY,
	MIDDLE,
	HARD
}Difficulty;

typedef struct {
	float volumn;
	int resolution_x;
	int resolution_y;
	Difficulty Difficulty;
}Settings;

//读取设置
void load_game_settings(const Settings* settings, const char* filename);

//保存设置
void save_game_settings(const Settings* settings, const char* filename);

int main(void)
{

	//fread
	//fwrite

	//二进制下的读与写

	Settings settings = { 0.75, 1920, 1080, MIDDLE };

	save_game_settings(&settings, "C:\\Users\\yangy\\Desktop\\log.txt");

	Settings load_setting = { 0 };

	load_game_settings(&load_setting, "C:\\Users\\yangy\\Desktop\\log.txt");

	printf("volunm : %f\nresolution_x : %d\nresolution_y : %d\ndifficulty : %d", load_setting.volumn, load_setting.resolution_x, load_setting.resolution_y, load_setting.Difficulty);

	return 0;
}

void save_game_settings(const Settings* settings, const char* filename) {
	FILE* file_stream = NULL;

	errno_t err = fopen_s(&file_stream, filename, "wb");

	if (err != 0 || file_stream == NULL) {
		char config_msg[256] = { 0 };

		strerror_s(config_msg, sizeof(config_msg), errno);
		fprintf(stderr, "Error to open the file: %s", config_msg);

		exit(EXIT_FAILURE);
	}

	//总共有四个参数,分别是指向缓冲区的指针,所读取数据的大小,每次读取的数目
	fwrite(settings, sizeof(Settings), 1, file_stream);

	fclose(file_stream);
}

void load_game_settings(const Settings* settings, const char* filename) {
	FILE* file_stream = NULL;

	errno_t err = fopen_s(&file_stream, filename, "rb");

	if (err != 0 || file_stream == NULL) {
		char config_msg[256] = { 0 };

		strerror_s(config_msg, sizeof(config_msg), errno);
		fprintf(stderr, "Error to open the file: %s", config_msg);

		exit(EXIT_FAILURE);
	}

	//总共有四个参数,分别是指向缓冲区的指针,所读取数据的大小,每次读取的数目
	fread(settings, sizeof(Settings), 1, file_stream);

	fclose(file_stream);
}

复制文件

#include 
#include 
#include 

int main(void)
{
	FILE* source_file = NULL;

	FILE* target_file = NULL;

	char source_path[] = "C:\\Users\\yangy\\Desktop\\abc.log";

	char target_path[] = "C:\\Users\\yangy\\Desktop\\log.txt";

	errno_t sourerr = fopen_s(&source_file, source_path, "rb");

	if (sourerr != 0 || source_file == NULL) {
		perror("Error to open source file");
		return EXIT_FAILURE;
	}

	errno_t tarerror = fopen_s(&target_file, target_path, "wb");

	if (tarerror != 0 || target_file == NULL) {
		perror("Error to open target file");
		return EXIT_FAILURE;
	}

	size_t byte_read = 0;

	char buffer[256] = { 0 };

	while ((byte_read = fread(buffer, 1, sizeof(buffer), source_file)) > 0) {
		fwrite(buffer, 1, byte_read, target_file);
	}

	_fcloseall();

	printf("succussfully");

	return 0;
}

fread函数原型

#include 
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

参数说明

  • ptr:指向用于存储读取数据的内存块的指针。该内存块的大小至少应该为 size * nmemb 字节,以确保能够容纳读取的数据。
  • size:每个数据项的大小(以字节为单位)。例如,如果要读取整数,size 可以设置为 sizeof(int)
  • nmemb:要读取的数据项的数量。函数将尝试读取 nmemb 个大小为 size 字节的数据项。
  • stream:指向 FILE 对象的指针,表示要从中读取数据的文件流。这个文件流通常是通过 fopen 函数打开的。

返回值

fread 函数返回实际成功读取的数据项的数量(而不是字节数)。如果发生错误或到达文件末尾,返回值可能小于 nmemb。具体情况如下:

  • 正常读取:返回成功读取的数据项数量,这个数量可能等于 nmemb,也可能小于 nmemb(例如,当接近文件末尾时)。
  • 到达文件末尾:返回值可能小于 nmemb,表示已经读取到文件末尾,没有足够的数据项可供读取。
  • 发生错误:如果在读取过程中发生错误,返回值也可能小于 nmemb。可以使用 ferror 函数检查是否发生了错误。

使用示例

#include 

#define ARRAY_SIZE 5

int main() {
    FILE *file = fopen("data.bin", "rb");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    int numbers[ARRAY_SIZE];
    size_t items_read = fread(numbers, sizeof(int), ARRAY_SIZE, file);

    if (items_read < ARRAY_SIZE) {
        if (feof(file)) {
            printf("已到达文件末尾,读取了 %zu 个整数。\n", items_read);
        } else if (ferror(file)) {
            perror("读取文件时发生错误");
        }
    } else {
        printf("成功读取 %zu 个整数。\n", items_read);
    }

    for (size_t i = 0; i < items_read; i++) {
        printf("numbers[%zu] = %d\n", i, numbers[i]);
    }

    fclose(file);
    return 0;
}

fwrite函数原型

#include 
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);

参数说明

  • ptr:指向要写入的数据的指针。该指针指向的数据块将被写入到文件流中。
  • size:每个数据项的大小(以字节为单位)。例如,如果要写入整数,size 通常设置为 sizeof(int);若写入字符,size 则为 sizeof(char)
  • nmemb:要写入的数据项的数量。函数会尝试将 nmemb 个大小为 size 字节的数据项写入文件流。
  • stream:指向 FILE 对象的指针,表示数据要写入的目标文件流。这个文件流一般是通过 fopen 函数打开的。

返回值

fwrite 函数返回实际成功写入的数据项的数量(并非字节数)。具体情况如下:

  • 正常写入:返回值等于 nmemb,表明所有指定的数据项都已成功写入文件流。
  • 部分写入或出错:返回值小于 nmemb,这意味着在写入过程中可能发生了错误,或者由于磁盘空间不足等原因,未能写入所有数据项。可以使用 ferror 函数来检查是否发生了错误。

使用示例

示例 1:写入整数数组到二进制文件
#include 

#define ARRAY_SIZE 5

int main() {
    FILE *file = fopen("data.bin", "wb");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    int numbers[ARRAY_SIZE] = {1, 2, 3, 4, 5};
    size_t items_written = fwrite(numbers, sizeof(int), ARRAY_SIZE, file);

    if (items_written < ARRAY_SIZE) {
        if (ferror(file)) {
            perror("写入文件时发生错误");
        }
    } else {
        printf("成功写入 %zu 个整数到文件。\n", items_written);
    }

    fclose(file);
    return 0;
}
示例 2:写入字符串到文件
#include 

int main() {
    FILE *file = fopen("text.txt", "w");
    if (file == NULL) {
        perror("无法打开文件");
        return 1;
    }

    char str[] = "Hello, World!";
    size_t items_written = fwrite(str, sizeof(char), sizeof(str), file);

    if (items_written < sizeof(str)) {
        if (ferror(file)) {
            perror("写入文件时发生错误");
        }
    } else {
        printf("成功写入字符串到文件。\n");
    }

    fclose(file);
    return 0;
}

 

来源于micro_frank

你可能感兴趣的:(c语言)