• 文件访问:C/C++/MFC


    1. C语言

    在C语言中,文件访问是通过一系列标准库函数来完成的,这些函数被定义在stdio.h(标准输入输出库)头文件中。
    文件的访问主要通过以下几个函数实现:

    函数说明
    fopen()打开一个文件
    fclose()关闭一个文件
    fread()读取文件
    fwrite()写入文件
    fseek()移动文件指针到指定位置
    ftell()获取文件指针当前位置
    fgetc()从文件中读取一个字符
    fputc()写入一个字符到文件中
    • Note:通过文件指针来实现文件的访问。
    1. 打开文件:
      FILE *fopen(const char *filename, const char *mode);
      此函数打开一个文件并返回一个文件指针,该文件指针可用于后续的文件操作。如果文件无法打开,则返回NULL。

      • filename 是文件名(可以包含路径)。
      • mode 是打开文件的模式,例如 “r”(只读)、“w”(只写,创建新文件或覆盖旧文件)、“a”(追加,写入数据到文件末尾)、“r+”(读写)等。
    2. 关闭文件:
      int fclose(FILE *stream);
      此函数关闭一个打开的文件。如果成功关闭文件,则返回0;否则返回EOF(一个定义在stdio.h中的特殊值,表示文件结束或发生错误)。

    3. 读取文件:
      size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
      此函数从文件中读取数据。函数返回实际读取的数据项的数量,如果发生错误或到达文件末尾,则可能小于count。

      • ptr 是一个指向内存块的指针,该内存块用于存储从文件中读取的数据。
      • size 是每个数据项的大小(以字节为单位)。
      • count 是要读取的数据项的数量。
      • stream 是文件指针。
    4. 写入文件:
      size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
      此函数将数据写入文件。函数返回实际写入的数据项的数量,如果发生错误,则可能小于count。

      • ptr 是一个指向要写入文件的数据的指针。
      • size、count 和 stream 的含义与fread相同。
    5. 文件定位:
      int fseek(FILE *stream, long offset, int whence);
      此函数设置文件位置指针。如果成功,则返回0;否则返回非零值。

      • offset 是相对于whence指定的位置的偏移量(以字节为单位)。
      • whence 可以是 SEEK_SET(文件开头)、SEEK_CUR(当前位置)或 SEEK_END(文件末尾)。
    6. 获取当前位置:
      long ftell(FILE *stream);
      此函数返回文件位置指针的当前位置(以字节为单位)。如果发生错误,则返回-1L。

    7. 检查文件结束:
      int feof(FILE *stream);
      此函数检查文件是否已到达末尾。如果到达末尾,则返回非零值;否则返回0。

    8. 清除文件结束和错误标志:
      void clearerr(FILE *stream);
      此函数清除与stream关联的文件结束和错误标志。

    9. 检查文件错误:
      int ferror(FILE *stream);
      此函数检查与stream关联的文件是否发生错误。如果发生错误,则返回非零值;否则返回0。

    10. 格式化输出或输入:
      int fscanf(FILE *fp, char *format, …);
      int fprintf(FILE *fp, char *format, …);

    11. 行输入和输出
      char *fgets(char *line, int maxline, FILE *fp);
      int fputs(char *line, FILE *fp);

    1.1 打开并读取文件

    #include 
    #include 
     
    int main() {
        FILE *file = fopen("test.txt", "r");
        if (file == NULL) {
            printf("无法打开文件\n");
            return -1;
        }
     
        char ch;
        while ((ch = fgetc(file)) != EOF) {
            printf("%c", ch);
        }
     
        fclose(file);
        return 0;
    }
    '
    运行

    1.2 写入文件

    #include 
    #include 
     
    int main() {
        FILE *file = fopen("test.txt", "w");
        if (file == NULL) {
            printf("无法打开文件\n");
            return -1;
        }
     
        fputc('A', file);
        fputc('B', file);
     
        fclose(file);
        return 0;
    }
    '
    运行

    1.3 读取二进制文件

    #include 
    #include 
     
    typedef struct {
        int a;
        char b;
    } Data;
     
    int main() {
        FILE *file = fopen("test.bin", "rb");
        if (file == NULL) {
            printf("无法打开文件\n");
            return -1;
        }
     
        Data data;
        fread(&data, sizeof(Data), 1, file);
     
        printf("a: %d, b: %c\n", data.a, data.b);
     
        fclose(file);
        return 0;
    }
    

    1.4 写入二进制文件

    #include 
    #include 
     
    typedef struct {
        int a;
        char b;
    } Data;
     
    int main() {
        FILE *file = fopen("test.bin", "wb");
        if (file == NULL) {
            printf("无法打开文件\n");
            return -1;
        }
     
        Data data = {1, 'A'};
        fwrite(&data, sizeof(Data), 1, file);
     
        fclose(file);
        return 0;
    }
    '
    运行

    1.5 文件指针的移动

    #include 
    #include 
     
    int main() {
        FILE *file = fopen("test.txt", "r");
        if (file == NULL) {
            printf("无法打开文件\n");
            return -1;
        }
     
        fseek(file, 2, SEEK_SET); // 将文件指针移动到第3个字符的位置
        printf("%c\n", fgetc(file));
     
        fclose(file);
        return 0;
    }
    '
    运行

    2. C++

    在C++中,文件访问与C语言非常相似,因为C++是在C语言的基础上构建的,并保留了C语言的大部分I/O功能。C++使用相同的文件操作函数,这些函数在(或)头文件中定义。然而,C++还提供了自己的文件流类(如std::ifstream、std::ofstream和std::fstream),这些类位于头文件中,提供了更加面向对象的文件操作方式。

    2.1 包含头文件

    #include 
    

    2.2 打开文件

    使用 std::ifstream(输入文件流)或 std::ofstream(输出文件流)来打开文件。例如:

    std::ifstream inputFile("input.txt"); // 打开文件以进行读取
    std::ofstream outputFile("output.txt"); // 打开文件以进行写入
    

    可以使用 std::fstream(文件流)来同时读取和写入文件。

    2.3 检查文件是否成功打开

    可以通过检查文件流对象是否有效来确认文件是否成功打开。

    if (!inputFile) {
        std::cerr << "无法打开文件\n";
        return 1;
    }
    

    2.4 读取文件

    使用 >> 运算符或 getline() 函数来从文件中读取数据。

    int number;
    inputFile >> number; // 读取一个整数
    
    std::string line;
    std::getline(inputFile, line); // 读取一行文本
    

    2.5 写入文件

    使用 << 运算符来将数据写入文件。

    outputFile << "Hello, World!\n"; // 写入一行文本
    outputFile << 42; // 写入一个整数
    
    TCHAR szFilter[] = _T("文本文档(*.txt)|*.txt|所有文件(*.*)|*.*||");
    	//构造保存文件对话框
    	CFileDialog fileDlg(FALSE, _T("txt"), NULL, 0, szFilter, this);
    	CString strFilePath;
    	//显示打开文件对话框
    	if (IDOK == fileDlg.DoModal())
    	{
    		strFilePath = fileDlg.GetPathName();
    		//AfxMessageBox(strFilePath);
    
    
    		std::ofstream file(strFilePath.GetBuffer()); // 打开文件
    		if (!file.is_open()) {
    			AfxMessageBox(_T("无法打开文件!\n"));
    			return;
    		}
    		std::string line;
    
    		// 逐行存储文件
    		int n = g_VeCRShowC.size();
    		for (int i = 0; i < n; i++)
    		{
    			file << g_VeSShowName[i] << " " << g_VeSShowType[i] << " " << "占地长: " << (g_VeCRShowC[i].Width()-40)/10 << "m  占地宽:" << (g_VeCRShowC[i].Height()-40)/10 <<"m"<< std::endl;
    		}
    		file.close();
    	}
    

    2.6 关闭文件

    当文件流对象超出范围或被销毁时,文件会自动关闭。但是,你也可以显式地调用 close() 方法来关闭文件。

    outputFile.close();
    

    2.7 文件指针的移动和获取位置

    使用 seekg()(对于输入流)和 seekp()(对于输出流)来移动文件指针。使用 tellg()(对于输入流)和 tellp()(对于输出流)来获取当前文件指针的位置。

    inputFile.seekg(10, std::ios::beg); // 将输入文件的指针移动到第10个字节
    std::streampos pos = inputFile.tellg(); // 获取当前输入文件的指针位置
    

    2.8 实例

    //读取文件
    #include 
    #include 
    #include 
    
    int main() {
        std::ifstream file("test.txt"); // 打开文件以供读取
    
        if (!file) { // 检查文件是否成功打开
            std::cerr << "无法打开文件\n";
            return 1;
        }
    
        std::string line;
        // 逐行读取文件
        while (std::getline(file, line)) {
            std::cout << line << '\n';
        }
    
        file.close(); // 关闭文件
        return 0;
    }
    
    //写入文件
    #include 
    #include 
    
    int main() {
        std::ofstream file("test.txt"); // 打开文件以供写入(如果文件不存在,则创建它)
    
        if (!file) { // 检查文件是否成功打开
            std::cerr << "无法打开文件\n";
            return 1;
        }
    
        file << "Hello, World!" << std::endl; // 写入数据到文件
    
        file.close(); // 关闭文件
        return 0;
    }
    

    C++的文件流类同样支持二进制文件的读写。你可以通过文件流的binary模式标志来指定文件应以二进制模式打开。但是,在大多数系统中,这并不是必须的,因为文件流默认就是二进制安全的。然而,在某些情况下(特别是跨平台操作时),明确指定二进制模式可能是有必要的。

    std::ifstream file("test.bin", std::ios::binary); // 以二进制模式打开文件
    // ... 读取操作 ...
    
    std::ofstream file("test.bin", std::ios::binary); // 以二进制模式打开文件
    // ... 写入操作 ...
    

    note:使用文件流类进行文件操作通常比使用C风格的函数更加直观和易于管理,因为它们提供了更丰富的错误处理和更面向对象的接口。此外,文件流还支持更多的操作,如格式化输入/输出、操纵符重载等.

    3. C语言和C++文件打开模式

    C++和C语言在文件打开模式上有很多相似之处,但由于C++提供了更高级的封装,其使用方式略有不同。以下是一个简化的表格,列出了C++和C语言中常用的文件打开模式:

    模式描述C++示例C示例
    “r”以只读方式打开文件,文件必须存在std::ifstream file(“test.txt”, std::ios::in);FILE *file = fopen(“test.txt”, “r”);
    “w”以写入方式打开文件,如果文件不存在则创建新文件,如果文件已存在则清空内容std::ofstream file(“test.txt”, std::ios::out);FILE *file = fopen(“test.txt”, “w”);
    “a”以追加方式打开文件,如果文件不存在则创建新文件,如果文件已存在则在文件末尾追加内容std::ofstream file(“test.txt”, std::ios::out/std::ios::app);FILE *file = fopen(“test.txt”, “a”);
    “r+”以读写方式打开文件,文件必须存在std::fstream file(“test.txt”, std::ios::in/std::ios::out);FILE *file = fopen(“test.txt”, “r+”);
    “w+”以写读方式打开文件,如果文件不存在则创建新文件,如果文件已存在则清空内容std::fstream file(“test.txt”, std::ios::in/std::ios::out/std::ios::truncFILE *file = fopen(“test.txt”, “w+”);
    “a+”以追加写读方式打开文件,如果文件不存在则创建新文件,如果文件已存在则在文件末尾追加内容std::fstream file(“test.txt”, std::ios::in /std::ios::out)
    “b”以二进制模式打开文件(可以与上述模式组合使用)std::ifstream file(“test.bin”, std::ios::in/std::ios::binary);

    4. MFC

    在MFC(Microsoft Foundation Classes)中,CFile 类是一个用于文件操作的封装类,它提供了比标准C语言I/O函数更高级和面向对象的接口。使用 CFile 类,你可以更方便地打开、读取、写入和关闭文件。

    4.1 头文件

    #include  // MFC 头文件
    #include     // 包含CFile类的定义
    

    4.2 打开文件

    CFile file(_T("example.txt"), CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive);
    if (!file.Open()) {
        AfxMessageBox(_T("无法打开文件"));
        return;
    }
    

    试图以创建(如果不存在)、写入和独占模式打开一个名为 example.txt 的文件。如果文件打开失败,显示一个消息框。

    4.3 写入文件

    CString str = _T("Hello, World!");
    ULONGLONG pos = file.GetPosition(); // 获取当前文件指针位置
    file.Write(str, (UINT)str.GetLength() * sizeof(TCHAR)); // 写入字符串到文件
    file.Seek(pos, CFile::begin); // 如果需要,可以将文件指针移回原位
    

    将一个字符串写入文件。Write 函数需要两个参数:要写入的数据的指针和要写入的数据的大小(以字节为单位)。

    4.4 读取文件

    ULONGLONG len = file.GetLength(); // 获取文件长度
    if (len > 0) {
        CFileException e;
        char* buffer = new char[len];
        try {
            file.Read(buffer, len); // 读取整个文件
        }
        catch (CFileException* pEx) {
            e = *pEx;
            pEx->Delete();
            // 处理异常
        }
        // 使用 buffer 中的数据...
        delete[] buffer; // 释放内存
    }
    

    在这个例子中,我们首先获取文件的长度,然后分配足够的内存来存储整个文件的内容。我们使用 Read 函数来读取文件内容。注意,我们使用 CFileException 来处理可能发生的异常。

    4.5 关闭文件

    file.Close(); // 关闭文件
    

    在完成文件操作后,使用 Close 函数关闭文件。虽然 CFile 的析构函数会自动关闭文件(如果尚未关闭),但显式关闭文件是一个好习惯。

    MFC 主要用于Windows桌面应用程序的开发,并且依赖于Microsoft的Visual C++环境。如果你正在开发跨平台应用程序或不想依赖MFC,那么使用标准C++的 库可能是更好的选择。

  • 相关阅读:
    12. 机器学习 - 拟合
    Windows 10重新安装微软商店Microsoft Store
    MySQL如何保证主备一致?
    Nginx 配置多个SSL域名指向不同端口
    支持百万并发的Web端即时通讯方案
    STL教程6-deque、stack、queue、list容器
    MySQL索引
    某大型国有银行 VMware 替换与轻量信创云底座转型实践 |信创专题
    分布式任务调度XXL-JOB-第二章-SpringBoot集成XXL-JOB
    Elasticsearch深入理解(十五)——版本冲突问题解决方案
  • 原文地址:https://blog.csdn.net/qingttqing/article/details/140447096