从 C 中的二进制文件中读取

reading from a binary file in C

我目前正在做一个项目,我必须从二进制文件中读取并通过套接字发送它,但我很难尝试发送整个文件。

这是我到目前为止写的:

        FILE *f = fopen(line,"rt");
        //size = lseek(f, 0, SEEK_END)+1;
        fseek(f, 0L, SEEK_END);
        int size = ftell(f);
        unsigned char buffer[MSGSIZE];
        FILE *file = fopen(line,"rb");
        while(fgets(buffer,MSGSIZE,file)){
            sprintf(r.payload,"%s",buffer);
            r.len = strlen(r.payload)+1;
            res = send_message(&r);
            if (res < 0) {
                perror("[RECEIVER] Send ACK error. Exiting.\n");
                return -1;
            }   
        }

我认为这与我读入的缓冲区大小有关,但我不知道它的正确公式是什么。

还有一点,sprintf 做对了吗?

不对,sprintf 没有正确完成。容易出现缓冲区溢出,非常严重的安全问题

我会考虑发送文件,例如1024 字节块而不是逐行,所以我会用 fread 调用替换 fgets 调用。

为什么要打开文件两次?显然是为了获取它的大小,但您只能打开它一次并跳回到文件的开头。而且,您没有使用阅读的尺寸。

如果您正在读取二进制文件,NUL 字符可能会出现在文件中的任何位置。

因此,使用像 sprintfstrlen 这样的字符串函数不是一个好主意。 如果你真的需要使用第二个缓冲区 (buffer),你可以使用 memcpy。 您也可以直接读入 r.payload(如果 r.payload 已经分配了足够的大小)。

您正在寻找 fread 二进制文件。 fread 的 return 值告诉您有多少字节被读入您的缓冲区。

您也可以考虑再次致电fseek。 看这里How can I get a file's size in C?

也许您的代码可能如下所示:

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

#define MSGSIZE 512

struct r_t {
  uint8_t payload[MSGSIZE];
  int len;
};

int send_message(struct r_t *t);

int main() {
  struct r_t r;
  FILE *f = fopen("test.bin","rb");
  fseek(f, 0L, SEEK_END);
  size_t size = ftell(f);
  fseek(f, 0L, SEEK_SET);
  do {
    r.len = fread(r.payload, 1, sizeof(r.payload), f);
    if (r.len > 0) {
      int res = send_message(&r);
      if (res < 0) {
        perror("[RECEIVER] Send ACK error. Exiting.\n");
        fclose(f);
        return -1;
      }
    }   
  } while (r.len > 0);
  fclose(f);
  return 0;
}

是二进制文件还是文本文件? fgets() 假设您正在读取一个文本文件——它在一个换行符处停止——但您说它是一个二进制文件并使用 "rb" 打开它(实际上,您第一次使用 [=17= 打开它],我认为这是一个错字)。

IMO 你永远不应该使用 sprintf。写入缓冲区的字符数取决于传入的参数,在这种情况下,如果缓冲区中没有'\0',则无法预测将复制多少字节到r.payload,并且有您很有可能会溢出该缓冲区。

我认为 sprintf() 将是第一个要修复的问题。使用 memcpy(),你可以准确地告诉它要复制多少字节。