最近因为用到了文件操作相关内容,所以趁着机会总结一下。这里主要介绍三种文件操作的方法,分别是C语言、C++以及WIN32里的文件操作方法。
所谓"文件",一般指存储在外部介质上数据的几何,一般数据都是以文件的形式存放在外部介质上的,而我们的操作系统是以文件为单位对数据进行管理的。
对文件进行分类,依据不同,分出的类别也不同。按介质可将文件分为:磁盘文件、光盘文件、U盘文件;按用途可将文件分为:程序文件(program file)、数据文件(data file);按文件中数据的组织形式可将文件分为:文件文件(以ascll表示文本文件,.txt .cpp .c)、二进制文件(用二进制表示文件 .o .exe .mp3 .bmp .png .jpg)。
c语言的文件操作:
1.头文件:stdio.h
2.文件是一个结构:FILE
3.文件指针:FILE* fp; //指向一个文件的指针
4.文件内部"指针":抽象的东西 “光标”
5.文件结束的标志:EOF
打开文件
FILE *fopen(char *filename,char * Mode);
以Mode方式打开filename文件,返回一个文件指针。
文本文档
r 只读 只能读取里面的内容 不能写!
w 只写 不管你打开的文件里面有什么,直接清空,可以写入数据
a 追加 文件的后面写入
r+ 读写 可以读取数据,写入,从内部指针开始覆盖
w+ 读写 清空文件,写读
a+ 读写 可以读可以写,文件的后面写入
二进制文档
rb 只读 只能读取里面的内容 不能写!
wb 只写 不管你打开的文件里面有什么,直接清空,可以写入数据
ab 追加 文件的后面写入
rb+ 读写 可以读取数据,写入,从内部指针开始覆盖
wb+ 读写 清空文件,写读
ab+ 读写 可以读可以写,文件的后面写入
文件打开失败的几种原因:
1.只读r r+的方式去打开一个不存在的文件
2.要打开的文件路径盘符不符合
3.文件名非法
4.文件被别的程序占用
关闭文件
fclose(fp)
不关闭文件,有可能导致数据丢失
读和写
fscanf 向文件格式化写入 fscanf(fp, “%d\t%s\t%f\n”, &pnew->num, pnew->name, &pnew->math)
fprintf 向文件格式化读取 fprintf(fp, “%d\t%s\t%f\n”, pStu->num, pStu->name, pStu->math);
fgetc 读一个字符串 char fgets(char str,int size,FILEfp);
fputc 写入一个字符串 int fputs(char str,FILE*fp);
fread 从文件fp读取数据 每一次读取size个字符 读取count次 保存在str,不会补充’\0’ size_t fread(void * str, size_t size, size_t count, FILE *fp);
fwrite 把str往分配写入,一次写入size个 写入count次 size_t fwrite(void * _Str, size_t Size, size_t Count,FILE *File);
fseek 移动文件内部指针 fseek(fp,offset,flag) fp 文件 offset 偏移量 flag 0头部 1当前位置 2文件尾
ftell 返回当前的内部指针相对于文件头的偏移量 int ftell(fp);
rewind 把文件内部指针直接移动到开头 rewind(fp);
fflush 清除读写缓冲区 int fflush(FILE *stream)
例子
// FILE.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include
#include
#include
#include
struct Camera
{
//Camera(void);
double focal_length = 0.0;
double distortion[2];
double translation[3];
double rotation[9];
bool is_constant = false;
};
struct Point3D
{
double pos[3];
bool is_constant = false;
};
struct Observation
{
double pos[2];
int camera_id;
int point_id;
};
std::vector<Camera> cameras;
std::vector<Point3D> points;
std::vector<Observation> observations;
void OpenFile(const char *filename,std::vector<Camera>& cams, std::vector<Point3D>& pts3D, std::vector<Observation>& observations)
{
FILE *fp;
if ((fp = fopen(filename, "r")) == NULL) //不存在
{
printf("\t\t\t文件不存在!");
return;
}
char line[15];
//加载相机参数
{
int n_cams;
fscanf(fp, "%s\t%d", line, &n_cams);
fgetc(fp);
cams.resize(n_cams);
for (int i = 0; i < cams.size(); i++)
{
fscanf(fp, "%lf", &cams[i].focal_length);
fscanf(fp, "%lf\t%lf", &cams[i].distortion[0], &cams[i].distortion[1]);
for (int j = 0; j < 3; j++)
fscanf(fp, "%lf\t", &cams[i].translation[j]);
for (int j = 0; j < 9; j++)
{
if (j == 8)
fscanf(fp, "%lf\n", &cams[i].rotation[j]);
else
fscanf(fp, "%lf\t", &cams[i].rotation[j]);
}
}
}
// 加载三维点
{
int n_points;
fscanf(fp, "%s\t%d\n", line, &n_points);
pts3D.resize(n_points);
for (int i = 0; i < n_points; i++)
fscanf(fp, "%lf\t%lf\t%lf\n", &pts3D[i].pos[0], &pts3D[i].pos[1], &pts3D[i].pos[2]);
}
//加载观察点
{
int n_observations;
fscanf(fp, "%s\t%d\n", line, &n_observations);
observations.resize(n_observations);
for (int i = 0; i < observations.size(); i++)
fscanf(fp, "%lf\t%lf\t%lf\t%lf\n", &observations[i].camera_id, &observations[i].point_id, &observations[i].pos[0], &observations[i].pos[1]);
}
}
int main()
{
OpenFile("test_ba.txt", cameras, points, observations);
return 0;
}
文件流
文件流是以外村文件为输入输出对象的数据流,每一个文件流都有一个内存缓冲区与之对应。其中输出文件流是从内存流向外村文件的数据,输入文件流是从外村文件流向内存的数据。
文件流本身不是文件,是以文件为输入输出对象的流,要对磁盘文件输入输出,必须通过文件流实现,即文件操作需要流对象,cout、cin是已定义的流对象。
文件流类
在C++的I/O类库中专门用于文件操作的类
要对文件输入输出,必须定义一个文件流类的对象
C++是通过流对象进行输入输出的,在用标准设备为对象的输入输出中,cin,cout是流对象。文件操作也是要定义流对象,例:ofstream outfile;
文本文件的读写
1) 打开磁盘文件
打开文件是指在文件读写之前做必要的准备工作:(1)为文件流对象和指定的磁盘文件建立关联,以便使文件流流向指定的磁盘文件;(2)指定文件的工作方式
打开文件的两种不同方法:(1)调用文件流的成员函数open,如ofstream outfile; outfile.open(“f1.dat”,ios::out); (2)在定义文件流对象时调用文件流类的构造函数,istream infile(“f1.dat”,ios::in);
2) 打开文件的方式
ios::in:供读,文件不存在时,打开失败(ifstream默认的打开方式)
ios::out:供写,文件不存在则创建,若文件存在,则清空原内容(ofstream默认的打开方式)
ios::ate:文件打开时,指针在文件最后;可改变指针的位置,常和in、out联合使用
ios::app:供写,文件不存在则创建,若文件已存在,则在原文件内容后添加写入新的内容
ios::trunc:在读写前先将文件长度截断为0(默认)
ios::nocreate:文件不存在时产生错误,常和in或app联合使用
ios::noreplace:文件存在时产生错误,常和out联合使用
ios::binary:二进制格式文件
3) 关闭文件
在对已打开的磁盘文件的读写操作完成后,应关闭该文件。
outfile.close(); //关闭磁盘文件"f1.dat"
关闭文件,将缓冲区中的数据妥善处理,解除了磁盘文件与文件流的关联,不再通过文件流对该文件进行输入或输出。
4) 文本文件的读写
文本文件,或称ASCII文件:文件中的每一个字节均以ASCII代码形式存放,即一个字节存放一个字符。
程序可以从文本文件中读入若干个字符,也可以向它输出一些字符。
对ASCII文件的读写操作的方法: (1)用流插入运算符“<<”和流提取运算符“>>”输入输出标准类型的数据。 (2)用文件流的put, get, geiline等成员函数进行字符的输入输出。
二进制文件的读写
1)对于数值数据的存储方式
short int a = 12345; //2个字节
文本形式:直观便于人阅读,占用内存较多,需要转换。
‘0’ 00110000
‘9’ 00111001
‘1’ ‘2’ ‘3’ ‘4’ ‘5’
00110001 00110010 00110011 00110100 00110101
二进制形式:计算机的内部形式,节省空间。不需要转换,但是不直观。
12345
00110000 00111001
2)读写二进制文件
打开方式
ofstream a(“file1.dat”, ios::out | ios::binary);
ifstream b(“file2.dat”,ios::in | ios::binary);
文件读写方式
istream& read(char *buffer,int len);
ostream& write(const char * buffer,int len);
char *buffer 指向内存中一段存储空间
int len 是读写的字节数
例:
a.write(p1,50) 将p1指向的空间中50个字节存入文件对象a
b.read(p2,30) 从文件对象b读出30个字节,存之指向空间
// FILE_C++.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include
#include
#include
#include
#include
#include
struct Camera
{
//Camera(void);
double focal_length = 0.0;
double distortion[2];
double translation[3];
double rotation[9];
bool is_constant = false;
};
struct Point3D
{
double pos[3];
bool is_constant = false;
};
struct Observation
{
double pos[2];
int camera_id;
int point_id;
};
std::vector<Camera> cameras;
std::vector<Point3D> points;
std::vector<Observation> observations;
void load_data(const std::string& file_name, std::vector<Camera>& cams, std::vector<Point3D>& pts3D, std::vector<Observation>& observations)
{
/* 加载数据 */
std::ifstream in(file_name);
assert(in.is_open());
std::string line, word;
//加载相机参数
{
int n_cams = 0;
getline(in, line);
std::stringstream stream(line);
stream >> word >> n_cams;
cams.resize(n_cams);
for (int i = 0; i < cams.size(); i++)
{
getline(in, line);
std::stringstream stream(line);
stream >> cams[i].focal_length;
stream >> cams[i].distortion[0] >> cams[i].distortion[1];
for (int j = 0; j < 3; j++)
stream >> cams[i].translation[j];
for (int j = 0; j < 9; j++)
stream >> cams[i].rotation[j];
}
}
// 加载三维点
{
int n_points = 0;
getline(in, line);
std::stringstream stream(line);
stream >> word >> n_points;
pts3D.resize(n_points);
for (int i = 0; i < n_points; i++) {
getline(in, line);
std::stringstream stream(line);
stream >> pts3D[i].pos[0] >> pts3D[i].pos[1] >> pts3D[i].pos[2];
}
}
//加载观察点
{
int n_observations = 0;
getline(in, line);
std::stringstream stream(line);
stream >> word >> n_observations;
observations.resize(n_observations);
for (int i = 0; i < observations.size(); i++) {
getline(in, line);
std::stringstream stream(line);
stream >> observations[i].camera_id
>> observations[i].point_id
>> observations[i].pos[0]
>> observations[i].pos[1];
}
}
}
int main()
{
load_data("../data/test_ba.txt", cameras, points, observations);
return 0;
}
创建或打开Windows文件
HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName, //文件名
_In_ DWORD dwDesiredAccess, //访问权限
_In_ DWORD dwShareMode, //共享模式
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, //安全属性
_In_ DWORD dwCreationDisposition, //文件创建模式
_In_ DWORD dwFlagsAndAttributes, //文件属性
_In_opt_ HANDLE hTemplateFile //文件模板
);
读写数据
写数据
BOOL WriteFile(
HANDLE hFile, //文件句柄
LPCVOID lpBuffer, //数据BUFF
DWORD nNumberOfBytesToWrite, //数据长度
LPDWORD lpNumberOfBytesWritten, //返回实际写入的数据
LPOVERLAPPED lpOverlapped //默认为NULL
);
读数据
BOOL ReadFile(
HANDLE hFile, //文件句柄
LPVOID lpBuffer, //数据BUFF
DWORD nNumberOfBytesToRead, //要读的字节数
LPDWORD lpNumberOfBytesRead, //实际读到字节数
LPOVERLAPPED lpOverlapped //默认为NULL
);
关闭文件
BOOL CloseHandle(
HANDLE hObject //文件句柄
);
相关函数
获取本机存在的驱动器
DWORD GetLogicalDrives(VOID);
获取系统盘的盘符
DWORD GetLogicalDriveStrings(
DWORD nBufferLength, //缓冲区大小
LPTSTR lpBuffer //接受数据的缓冲区
);
获取盘符类型
UINT GetDriveType( LPCTSTR lpRootPathName //盘符根目录
);
返回值:
DRIVE_UNKNOWN - 驱动器类型不能确定。
DRIVE_NO_ROOT_DIR - 根目录不存在。
DRIVE_REMOVABLE - 可移动磁盘。
DRIVE_FIXED - 本地磁盘
DRIVE_REMOTE - 远程(网络)驱动器。
DRIVE_CDROM - CD-ROM驱动器。
DRIVE RAMDISK - RAM磁盘。
获取程序当前工作目录
DWORD GetCurrentDirectory(
DWORD nBufferLength, //缓冲区大小
LPTSTR lpBuffer //接受数据的缓冲区
);
设置程序当前工作目录
BOOL SetCurrentDirectory(
LPCTSTR lpPathName //要设置的目录名
);
获取Windows目录
UINT GetWindowsDirectory(
LPTSTR lpBuffer, //接受数据的缓冲区
UINT uSize //缓冲区大小
);
获取Windows的System目录
UINT GetSystemDirectory(
LPTSTR lpBuffer, //接受数据的缓冲区
UINT uSize //缓冲区大小
);
获取临时文件目录
DWORD GetTempPath(
DWORD nBufferLength, //接受数据的缓冲区
LPTSTR lpBuffer //缓冲区大小
);
创建目录
BOOL CreateDirectory(
LPCTSTR lpPathName, //目录名称
LPSECURITY_ATTRIBUTES lpSecurityAttributes //安全属性,默认为NULL
);
删除目录
BOOL RemoveDirectory(
LPCTSTR lpPathName //目录名称(目录中不能包含子目录或文件)
);
移动目录
BOOL MoveFile(
LPCTSTR lpExistingFileName, //已存在的目录
LPCTSTR lpNewFileName //新的路径(不能跨盘移动)
);
获取文件长度
DWORD GetFileSize(
HANDLE hFile, //文件句柄
LPDWORD lpFileSizeHigh
);
文件指针
DWORD SetFilePointer(
HANDLE hFile, //文件句柄
LONG lDistanceToMove, //偏移量的低32位
PLONG lpDistanceToMoveHigh, //偏移量的高32位
DWORD dwMoveMethod //偏移的相对位置
);
拷贝文件
BOOL CopyFile(
LPCTSTR lpExistingFileName, //源文件名
LPCTSTR lpNewFileName, //目标文件名
BOOL bFailIfExists //如果设为TRUE(非零),那么一旦目标文件已经存在,则函数调用会失败。否则目标文件被改写
);
删除文件
BOOL DeleteFile(
LPCSTRlpFileName //要删除的文件名的指针
);
移动文件
BOOL MoveFile(
LPCTSTR lpExistingFileName, //一个存在的文件或者文件夹字符串指针
LPCTSTR lpNewFileName //个还没存在的文件或者文件夹的字符串指针
);
获取文件属性
DWORD WINAPI GetFileAttributes(
__in LPCTSTR lpFileName //文件或目录的名字,对于ANSI版本,名字不能大于MAX_PATH(260)
);
设置文件属性
BOOL SetFileAttributes(
LPCTSTR lpFileName, //要设置其属性的文件名
DWORD dwFileAttributes //文件属性
);
获取文件属性、时间等
BOOL GetFileAttributesEx(
LPCTSTR lpFileName, //指向指定文件或目录的字符串的指针
GET_FILEEX_INFO_LEVELS fInfoLevelId, //指定要获取的属性信息的类型的值
LPVOID lpFileInformation //指向缓冲区的指针,以接收属性信息
);
查找文件
HANDLE FindFirstFile(
LPCTSTR lpFileName, //查找路径
LPWIN32_FIND_DATA lpFindFileData //查找的数据
);
获取下一个文件
BOOL FindNextFile(
HANDLE hFindFile, //查找句柄
LPWIN32_FIND_DATA lpFindFileData //查找的数据
);
关闭查找
BOOL FindClose(
HANDLE hFindFile //查找句柄
);
例子
// FILE_WIN32.cpp : 文件打开读写。
//
#include
#include
int main(int argc, char *argv[])
{
HANDLE handle = CreateFile(L"../data/abc.dat", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (handle == INVALID_HANDLE_VALUE)
{
printf("打开文件失败!%d\n", GetLastError());
return -1;
}
//写文件
DWORD realWrittenBytes = 0;
BOOL ret = WriteFile(handle, "hello,world", strlen("hello,world"), &realWrittenBytes, 0);
if (ret == 0)
{
printf("写入文件失败!%d\n", GetLastError());
return -1;
}
//追加数据
SetFilePointer(handle, 0, 0, FILE_END);
WriteFile(handle, "你好,世界", strlen("你好,世界"),&realWrittenBytes, 0);
//获取文件的大小
DWORD loSize = 0, hiSize = 0;
loSize = GetFileSize(handle, &hiSize);
printf("low Size = %d, High Size = %d\n", loSize, hiSize);
//关闭文件句柄
CloseHandle(handle);
return 0;
}
//遍历查找文件
#include
#include
void findFile(char* pathName);
//遍历目录
int main(int argc, char* argv[])
{
char curPath[MAX_PATH] = { 0 };
GetCurrentDirectory(MAX_PATH, (LPSTR)curPath);
printf("%s", &curPath);
findFile(curPath);
return 0;
}
bool isDotOrDotdot(char* pathName)
{
if (strcmp(pathName, ".") == 0 ||
strcmp(pathName, "..") == 0)
return true;
return false;
}
void findFile(char* pathName)
{
char fileFileName[_MAX_PATH] = { 0 };
sprintf_s(fileFileName, "%s\\*", pathName); //查找当前目录下的所有文件
WIN32_FIND_DATA findData;
HANDLE handle = FindFirstFile(fileFileName, &findData); //尝试找第一个文件
if (handle == INVALID_HANDLE_VALUE)
{
printf("没有文件\n");
return;
}
BOOL bFind = TRUE;
char szTemp[MAX_PATH] = { 0 };
while (bFind)
{
if (findData.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
if (!isDotOrDotdot(findData.cFileName))
{
sprintf_s(szTemp, "%s\\%s", pathName, findData.cFileName);
printf("文件夹 : %s\n", szTemp);
findFile(szTemp);
}
}
else
{
memset(szTemp, 0x00, MAX_PATH);
sprintf_s(szTemp, "%s\\%s\n", pathName, findData.cFileName);
printf("fileName : %s", szTemp);
}
//继续查找下一个文件,如果找不到,则返回FALSE
bFind = FindNextFile(handle, &findData);
}
}