如何读取/写入二进制文件?

2024-10-17 08:47:00
admin
原创
86
摘要:问题描述:我正在尝试写入二进制文件、从中读取并输出到屏幕。我可以写入文件,但是当我尝试读取文件时,输出不正确。解决方案 1:读取和写入二进制文件与读取和写入任何其他文件几乎相同,唯一的区别在于打开方式:unsigned char buffer[10]; FILE *ptr; ptr = fopen(&...

问题描述:

我正在尝试写入二进制文件、从中读取并输出到屏幕。

我可以写入文件,但是当我尝试读取文件时,输出不正确。


解决方案 1:

读取和写入二进制文件与读取和写入任何其他文件几乎相同,唯一的区别在于打开方式:

unsigned char buffer[10];
FILE *ptr;

ptr = fopen("test.bin","rb");  // r for read, b for binary

fread(buffer,sizeof(buffer),1,ptr); // read 10 bytes to our buffer

您说您可以读取它,但是它没有正确输出...请记住,当您“输出”这些数据时,您并没有读取 ASCII,因此它不像在屏幕上打印字符串:

for(int i = 0; i<10; i++)
    printf("%u ", buffer[i]); // prints a series of bytes

写入文件几乎相同,不同之处fwrite()在于您使用的是fread()

FILE *write_ptr;

write_ptr = fopen("test.bin","wb");  // w for write, b for binary

fwrite(buffer,sizeof(buffer),1,write_ptr); // write 10 bytes from our buffer

既然我们在谈论 Linux,那么有一种简单的方法可以进行健全性检查。hexdump在您的系统上安装(如果尚未安装)并转储您的文件:

mike@mike-VirtualBox:~/C$ hexdump test.bin
0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000010 0001 003e 0001 0000 0000 0000 0000 0000
...

现在将其与您的输出进行比较:

mike@mike-VirtualBox:~/C$ ./a.out 
127 69 76 70 2 1 1 0 0 0

嗯,也许将 改为printfa%x会使它更清楚一些:

mike@mike-VirtualBox:~/C$ ./a.out 
7F 45 4C 46 2 1 1 0 0 0

嘿,看!数据现在匹配了*。太棒了,我们一定正确读取了二进制文件!

*请注意,输出中的字节只是被交换了,但数据是正确的,你可以针对这种情况进行调整

解决方案 2:

有几种方法可以做到这一点。如果我想读写二进制文件,我通常使用,,,open()。这与一次处理一个字节完全不同。您使用整数文件描述符而不是 FILE 变量。fileno 将从 FILE BTW 获取一个整数描述符。您一次读取一个充满数据的缓冲区,比如说 32k 字节。缓冲区实际上是一个数组,因为它在内存中,所以您可以从中快速读取。一次读写多个字节比一次读写一个字节要快。我认为它在 Pascal 中被称为 blockread,但 read() 是 C 中的等价物。read()`write()`close()

我查看了,但手头没有任何示例。好吧,这些并不理想,因为它们也处理 JPEG 图像。这是一个读取,您可能只关心从 open() 到 close() 的部分。fbuf 是要读入的数组,sb.st_size 是来自 stat() 调用的文件大小(以字节为单位)。

    fd = open(MASKFNAME,O_RDONLY);
    if (fd != -1) {
      read(fd,fbuf,sb.st_size);
      close(fd);
      splitmask(fbuf,(uint32_t)sb.st_size); // look at lines, etc
      have_mask = 1;
    }

这里是写入:(这里 pix 是字节数组,jwidth 和 jheight 是 JPEG 宽度和高度,因此对于 RGB 颜色,我们写入高度 宽度 3 个颜色字节)。这是要写入的字节数。

void simpdump(uint8_t *pix, char *nm) { // makes a raw aka .data file
  int sdfd;
  sdfd = open(nm,O_WRONLY | O_CREAT);
  if (sdfd == -1) {
    printf("bad open
");
    exit(-1);
  }
  printf("width: %i height: %i
",jwidth,jheight);  // to the console
  write(sdfd,pix,(jwidth*jheight*3));
  close(sdfd);
}

查看 man 2 open,还有 read、write、close。还有这个旧式 jpeg example.c:https://github.com/LuaDist/libjpeg/blob/master/example.c 我在这里一次读取和写入整个图像。但它们是二进制字节读取和写入,只是一次读取很多。

“但是当我尝试从文件中读取时,它无法正确输出。”嗯。如果您读取数字 65,则 A 的 ASCII 码为(十进制)。也许您也应该查看 man ascii。如果您想要 1,则 ASCII 码为 0x31。char 变量实际上是一个很小的 ​​8 位整数,如果您将 printf 作为 %i 执行,您将获得 ASCII 值,如果您执行 %c,您将获得字符。执行 %x 表示十六进制。全部来自 0 到 255 之间的相同数字。

解决方案 3:

我对我“制作一个弱引脚存储程序”的解决方案非常满意。也许它会对那些需要一个非常简单的二进制文件 IO 示例来遵循的人有所帮助。

$ ls
WeakPin  my_pin_code.pin  weak_pin.c
$ ./WeakPin
Pin: 45 47 49 32
$ ./WeakPin 8 2
$ Need 4 ints to write a new pin!
$./WeakPin 8 2 99 49
Pin saved.
$ ./WeakPin
Pin: 8 2 99 49
$
$ cat weak_pin.c
// a program to save and read 4-digit pin codes in binary format

#include <stdio.h>
#include <stdlib.h>

#define PIN_FILE "my_pin_code.pin"

typedef struct { unsigned short a, b, c, d; } PinCode;


int main(int argc, const char** argv)
{
    if (argc > 1)  // create pin
    {
        if (argc != 5)
        {
            printf("Need 4 ints to write a new pin!
");
            return -1;
        }
        unsigned short _a = atoi(argv[1]);
        unsigned short _b = atoi(argv[2]);
        unsigned short _c = atoi(argv[3]);
        unsigned short _d = atoi(argv[4]);
        PinCode pc;
        pc.a = _a; pc.b = _b; pc.c = _c; pc.d = _d;
        FILE *f = fopen(PIN_FILE, "wb");  // create and/or overwrite
        if (!f)
        {
            printf("Error in creating file. Aborting.
");
            return -2;
        }

        // write one PinCode object pc to the file *f
        fwrite(&pc, sizeof(PinCode), 1, f);  

        fclose(f);
        printf("Pin saved.
");
        return 0;
    }

    // else read existing pin
    FILE *f = fopen(PIN_FILE, "rb");
    if (!f)
    {
        printf("Error in reading file. Abort.
");
        return -3;
    }
    PinCode pc;
    fread(&pc, sizeof(PinCode), 1, f);
    fclose(f);

    printf("Pin: ");
    printf("%hu ", pc.a);
    printf("%hu ", pc.b);
    printf("%hu ", pc.c);
    printf("%hu
", pc.d);
    return 0;
}
$

解决方案 4:

这是读写二进制 jjpg 或 wmv 视频文件的示例。FILE fout;FILE fin;

Int ch;
char *s;
fin=fopen("D:\\pic.jpg","rb");
if(fin==NULL)
     {  printf("
 Unable to open the file ");
         exit(1);
      }

 fout=fopen("D:\\ newpic.jpg","wb");
 ch=fgetc(fin);
       while (ch!=EOF)
             { 
                  s=(char *)ch;
                  printf("%c",s);
                 ch=fgetc (fin):
                 fputc(s,fout);
                 s++;
              }

        printf("data read and copied");
        fclose(fin);
        fclose(fout);

解决方案 5:

我费了好大劲才找到一种方法,用 C++ 将二进制文件读入字节数组,并输出我在十六进制编辑器中看到的十六进制值。经过多次尝试和错误,这似乎是最快的方法,无需额外的强制转换。默认情况下,它会将整个文件加载到内存中,但只打印前 1000 个字节。

string Filename = "BinaryFile.bin";
FILE* pFile;
pFile = fopen(Filename.c_str(), "rb");
fseek(pFile, 0L, SEEK_END);
size_t size = ftell(pFile);
fseek(pFile, 0L, SEEK_SET);
uint8_t* ByteArray;
ByteArray = new uint8_t[size];
if (pFile != NULL)
{
    int counter = 0;
    do {
        ByteArray[counter] = fgetc(pFile);
        counter++;
    } while (counter <= size);
    fclose(pFile);
}
for (size_t i = 0; i < 800; i++) {
    printf("%02X ", ByteArray[i]);
}

解决方案 6:

这个问题与 CAMILO HG 的“如何用 C 编写二进制数据文件并使用 Gnuplot 绘制”问题相关。我知道真正的问题有两个部分:1) 编写二进制数据文件,2) 使用 Gnuplot 绘制。

第一部分已经在这里得到非常清楚的回答了,所以我没有什么可补充的。

对于第二种情况,最简单的方法是让人们查阅 Gnuplot 手册,我确信有人能找到好的答案,但我在网上找不到,所以我要解释一个解决方案(这肯定是在真正的问题中,但我是 stackoverflow 的新手,我无法在那里回答):

使用 写入二进制数据文件后fwrite(),您应该用 C 语言创建一个非常简单的程序,即读取器。读取器只包含与写入器相同的结构,但您使用fread()fwrite()因此,生成此程序非常容易:将reader.c原始代码的写入部分复制到文件中,并将 write 更改为 read(将“wb”更改为“rb”)。此外,您还可以对数据进行一些检查,例如,检查文件的长度是否正确。最后,您的程序需要使用 在标准输出中打印数据printf()

要清楚:你的程序像这样运行

$ ./reader data.dat

X_position Y_position  (it must be a comment for Gnuplot)*

1.23 2.45

2.54 3.12

5.98 9.52

好的,使用这个程序,在 Gnuplot 中你只需要将读取器的标准输出通过管道传输到 Gnuplot,如下所示:

plot '< ./reader data.dat'

这一行,运行程序阅读器,输出与 Gnuplot 连接并绘制数据。

*因为 Gnuplot 要读取程序的输出,所以您必须知道 Gnuplot 可以读取和绘制什么,不能读取和绘制什么。

解决方案 7:

#include <stdio.h> 
#include <stdlib.h> 

main(int argc, char **argv) //int argc; char **argv;
{ 
 int wd;
 FILE *in, *out; 

  if(argc != 3) {
    printf("Input and output file are to be specified
");
    exit(1);
  }
  in = fopen(argv[1], "rb");
  out = fopen(argv[2], "wb");
  if(in == NULL || out == NULL) { /* open for write */ 
    printf("Cannot open an input and an output file.
");
    getchar();
    exit(0); 
  } 
  while(wd = getw(in), !feof(in)) putw(wd, out); 

  fclose(in);
  fclose(out);

}
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用