在C++中进行文件读写有多种方法,在这里介绍其中的一种,只需要最基本的iostream
头文件即可。
代码
#include <iostream>
using namespace std;
// 文件路径
const char* inPath = "...";
const char* outPath = "...";
int main()
{
// 文件指针
FILE* inFile;
FILE* outFile;
// 文件总字节数
int inFileSize;
int outFileSize;
// 打开文件
if (fopen_s(&inFile, inPath, "rb") == 0)
{
cout << "Successfully opened the original file." << endl;
}
else
{
cout << "Failed to open the original file." << endl;
}
// 被标记为“不安全”的方法
/* if ((inFile = fopen(inPath, "rb")) == NULL)
{
cout << "Failed to open the original file." << endl;
}
else
{
cout << "Successfully opened the original file." << endl;
} */
// 计算文件总字节数
fseek(inFile, 0L, SEEK_END); // 使文件指针指向文件末尾
inFileSize = ftell(inFile); // 文件总字节数
rewind(fp); // 再使文件指针指回文件起始
// 建立缓冲区
// 方法1(C++)
unsigned char* inBuffer = new unsigned char[inFileSize];
unsigned char* outBuffer = new unsigned char[outFileSize];
// 方法2(C/C++)
// unsigned char* inBuffer = (unsigned char*)malloc(inFileSize);
// unsigned char* outBuffer = (unsigned char*)malloc(outFileSize);
// 将数据读入缓冲区
fread(inBuffer, sizeof(unsigned char), inFileSize, inFile);
// 对outBuffer进行处理……
// 将处理后的数据写入新文件
fwrite(outBuffer, sizeof(unsigned char), outFileSize, outFile);
//格式化输出到文件
fprintf(outFile, "Hello world!");
// 关闭文件
fclose(inFile);
fclose(outFile);
// 释放内存
// 对应new的方法
delete[]inBuffer;
delete[]outBuffer;
// 对应malloc的方法
// free(inBuffer);
// free(outBuffer);
}
说明
文件路径
文件路径一般建议使用绝对路径。
在Windows中,文件路径名中的“\”需要手动改为“\\”,macOS文件路径的“/”不需要作修改。
fopen_s
函数
-
功能:打开文件
-
函数原型:
errno_t fopen_s(FILE** _Stream, const char* _FileName, const char* _Mode);
-
参数:
-
_Stream
:文件指针;对应的实参写法应为&_Stream
-
_FileName
:文件名称(路径) -
_Mode
:访问方式(常用访问方式如下表所示;后缀b
表示以二进制的方式打开)访问方式 含义 "r"
/"rb"
只读:打开一个已有的文件 "w"
/"wb"
只写:打开一个空文件进行写入(若该文件存在则会被覆盖) "a"
/"ab"
追加:打开一个文件进行追加写入(若文件不存在将会新建该文件) "r+"
/"rb+"
读写:对一个已有的文件进行读或写 "w+"
/"wb+"
只读:打开一个空文件进行读写(若该文件存在则会被覆盖) "a+"
/"ab+"
读+追加:打开一个文件进行读取和追加写入(若文件不存在将会新建该文件)
-
-
返回值:
0
表示读取成功,其他情况均表示读取失败(但含义各有不同,在此不一一列举) -
有关
fopen
函数:函数原型为FILE fopen(const char* _FileName, const char* _Mode);
,用法与fopen_s
类似(但返回值为NULL
表示读取失败)。但在Visual Studio中进行C++的编译会出现C4996错误:
fopen编译报错这是由于该函数被标记为不安全的CRT库函数,因此建议使用更安全的
fopen_s
函数代替。若仍要使用,转到菜单栏 → 项目 → 属性,点击属性配置 → C/C++ → 预处理器,在预处理器定义中添加一项_CRT_SECURE_NO_WARNINGS
(如图),或在代码中添加一行#define _CRT_SECURE_NO_WARNINGS
即可消除掉该报错。
消除C4996错误
fseek
函数
-
功能:重新定位文件指针的指向
-
函数原型:
int fseek(FILE* _Stream, long _Offset, int _Origin);
-
参数:
-
_Stream
:文件指针 -
_Offset
:(长整型)相对于_Origin
的偏移量(正数表示正向偏移,负数反之) -
_Origin
:偏移量的参考基准。可取值为:偏移基准 含义 SEEK_SET
(或0
)文件起始 SEEK_CUR
(或1
)文件当前位置 SEEK_END
(或2
)文件结尾
-
-
例如
fseek(fp, -100L, SEEK_END);
表示将文件指针退回到距离文件结尾100字节处 -
rewind(fp)
功能也是文件指针的定位,只不过是定位到文件起始,相当于fseek(fp, 0L, 0);
ftell
函数
- 功能:返回文件指针当前位置(用相对于文件起始的偏移量表示)
- 函数原型:
long ftell(FILE* _Stream);
动态分配内存
在C中,动态分配内存的方式有三种:malloc
(本文采用)、calloc
、realloc
,略有区别(可以参考一下这位大佬的博客:C/C++动态内存分配),对应地,释放内存使使用free
函数;C++中该方法仍然可用,也可以使用new
标识符进行内存分配,在释放内存时,相应使用delete[]
。
fread
/fwrite
函数
- 功能:读/写数据块
- 函数原型:
size_t fread(void* _Buffer, size_t _ElementSize, size_t ElementCount, FILE* _Stream);
(fwrite
完全相同) - 参数:
_Buffer
:数据块的首地址(例如缓冲区指针名)_ElementSize
:每个要读/写地数据块的字节数_ElementCount
:要读/写的数据块数(在功能上,只要保证_ElementSize
和_ElementCount
的乘积正确即可)_Stream
:要读/写的文件指针
- 返回值:成功读取的数据块数(可以用来输出并检查错误)
fprintf
函数
- 功能:格式化输出到指定流文件
- 函数原型:
int fprintf(FILE* _Stream, const char* _Format, [argument]);
- 参数:第一个参数为要输出的文件的文件指针,其余参数与
printf
函数完全相同 - 返回值:读取成功,返回I/O的个数;出错或文件尾,返回
EOF
- 类似地,也有
fscanf
函数,具体用法不再赘述
fclose
函数
- 功能:关闭文件
- 函数原型:
int fclose(FILE* _Stream);