【问题标题】:fprintf() writes data in text format regardless to the mode I use in fopen() to open the filefprintf() 以文本格式写入数据,无论我在 fopen() 中使用何种模式打开文件
【发布时间】:2023-05-21 14:41:01
【问题描述】:

尝试使用 fprintf() 以二进制模式存储 int,但无论我在 fopen() 中指定哪种模式,它都仅以文本格式写入 int 值。另一方面,当我使用fwrite 代替fprintf 时,它以二进制格式存储int。那么我们可以在二进制模式下使用fprintf吗?

#include <stdio.h>

int main()
{
    FILE *fp;
    fp = fopen("abc.bin", "wb");
    int num = 69;
    fprintf(fp, "%d", num);
    fclose(fp);
    return 0;
}

另外,如果我们谈论其他 I/O 函数,它们中的哪一个将在二进制模式下完美工作?是否有任何关于此类行为的正式记录?

我在mingw下的windows平台上工作。

【问题讨论】:

  • fprintf%d 总是将整数转换为字符序列。这就是它所做的定义。如果您想以原始二进制形式写入数据,请使用fwrite
  • 所以要以原始二进制形式实际存储数据,我们可以使用除fwrite之外的任何其他函数吗?
  • fwrite 是用于写入原始二进制数据的stdio 函数。请注意,使用"w""wb" 打开文件之间的差异相当小。它实际上只影响如何在 Windows 系统上处理换行符。在 Unix 系统上没关系。
  • 对二进制数据使用"wb" 更安全。它保证您的数据不会被更改。在 Windows 系统上使用"w" 的风险在于,如果您编写一个看起来像换行符的字节,则存在在其前面插入回车符的风险。不幸的是,Windows 很早就在如何处理行尾问题上做出了错误的选择,但现在就是这样。
  • 公平地说,Windows 并没有发明 cr/lf 行尾序列。大多数 DEC 操作系统都使用它,而 Unix 使用单个换行符。因此,在 Unix 变得像今天这样流行之前,Windows 做了 DEC 所做的事情。对包含二进制数据的文件使用"wb",对文本文件使用"w",不会有任何问题。

标签: c file-io integer binaryfiles fwrite


【解决方案1】:

fprintf() 旨在将int 参数转换为人类可读的格式。要将二进制数据存储到您的文件中,您确实必须使用"wb""ab" 以二进制模式打开它,您可以使用fwriteputc

int n = 1234;
if (fwrite(&n, sizeof(n), 1, fp) == 1) {
    // n was successfully written to fp
}

fwrite 使用运行系统中使用的表示和字节顺序存储int 值。如果文件可以传输到不同的系统读取,则必须指定文件中使用的字节顺序和表示,并以可移植的方式实现读取和写入功能:

#include <stdio.h>
#include <stdint.h>

int write_int32_le(int n, FILE *fp) {
    /* write the int as a 4 byte little endian two's complement representation */
    uint32_t u32 = n;
    int res = 4;
    for (int i = 0; i < 4; i++) {
        if (putc(u32 & 255, fp) == EOF)
            res = EOF;
        u32 >>= 8;
    }
    return res;
}

int read_int32_le(FILE *fp) {
    /* write the int as a 4 byte little endian two's complement representation */
    uint32_t u32 = 0;
    for (int i = 0; i < 4; i++) {
        int c = getc(fp);
        if (c == EOF)
            return EOF;
        u32 |= (uint32_t)c << (i << 3);
    }
    return (int)u32;
}

您的二进制文件中可以使用其他表示形式,例如 big-endian 或 LEB128

【讨论】:

    最近更新 更多