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

文章目录

  • [1. C语言](#1. C语言)
    • [1.1 打开并读取文件](#1.1 打开并读取文件)
    • [1.2 写入文件](#1.2 写入文件)
    • [1.3 读取二进制文件](#1.3 读取二进制文件)
    • [1.4 写入二进制文件](#1.4 写入二进制文件)
    • [1.5 文件指针的移动](#1.5 文件指针的移动)
  • [2. C++](#2. C++)
    • [2.1 包含头文件](#2.1 包含头文件)
    • [2.2 打开文件](#2.2 打开文件)
    • [2.3 检查文件是否成功打开](#2.3 检查文件是否成功打开)
    • [2.4 读取文件](#2.4 读取文件)
    • [2.5 写入文件](#2.5 写入文件)
    • [2.6 关闭文件](#2.6 关闭文件)
    • [2.7 文件指针的移动和获取位置](#2.7 文件指针的移动和获取位置)
    • [2.8 实例](#2.8 实例)
  • [3. C语言和C++文件打开模式](#3. C语言和C++文件打开模式)
  • [4. MFC](#4. MFC)
    • [4.1 头文件](#4.1 头文件)
    • [4.2 打开文件](#4.2 打开文件)
    • [4.3 写入文件](#4.3 写入文件)
    • [4.4 读取文件](#4.4 读取文件)
    • [4.5 关闭文件](#4.5 关闭文件)

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 打开并读取文件

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
 
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 写入文件

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
 
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 读取二进制文件

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
 
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 写入二进制文件

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
 
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 文件指针的移动

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
 
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++使用相同的文件操作函数,这些函数在(或<stdio.h>)头文件中定义。然而,C++还提供了自己的文件流类(如std::ifstream、std::ofstream和std::fstream),这些类位于头文件中,提供了更加面向对象的文件操作方式。

2.1 包含头文件

cpp 复制代码
#include <fstream>

2.2 打开文件

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

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

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

2.3 检查文件是否成功打开

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

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

2.4 读取文件

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

cpp 复制代码
int number;
inputFile >> number; // 读取一个整数

std::string line;
std::getline(inputFile, line); // 读取一行文本

2.5 写入文件

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

cpp 复制代码
outputFile << "Hello, World!\n"; // 写入一行文本
outputFile << 42; // 写入一个整数

2.6 关闭文件

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

cpp 复制代码
outputFile.close();

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

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

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

2.8 实例

cpp 复制代码
//读取文件
#include <fstream>
#include <iostream>
#include <string>

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;
}
cpp 复制代码
//写入文件
#include <fstream>
#include <iostream>

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模式标志来指定文件应以二进制模式打开。但是,在大多数系统中,这并不是必须的,因为文件流默认就是二进制安全的。然而,在某些情况下(特别是跨平台操作时),明确指定二进制模式可能是有必要的。

cpp 复制代码
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::trunc FILE *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 头文件

cpp 复制代码
#include <afxwin.h> // MFC 头文件
#include <afx.h>    // 包含CFile类的定义

4.2 打开文件

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

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

4.3 写入文件

cpp 复制代码
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 读取文件

cpp 复制代码
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 关闭文件

cpp 复制代码
file.Close(); // 关闭文件

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

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

相关推荐
网易独家音乐人Mike Zhou3 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
‘’林花谢了春红‘’4 小时前
C++ list (链表)容器
c++·链表·list
搬砖的小码农_Sky6 小时前
C语言:数组
c语言·数据结构
机器视觉知识推荐、就业指导6 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
Yang.998 小时前
基于Windows系统用C++做一个点名工具
c++·windows·sql·visual studio code·sqlite3
熬夜学编程的小王8 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
zz40_8 小时前
C++自己写类 和 运算符重载函数
c++
六月的翅膀8 小时前
C++:实例访问静态成员函数和类访问静态成员函数有什么区别
开发语言·c++
liujjjiyun9 小时前
小R的随机播放顺序
数据结构·c++·算法