我目前正在开发一个项目,我必须从二进制文件中读取并通过套接字发送它,并且我很难尝试发送整个文件。
这是我到目前为止所写的内容:
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是否正确完成了?
答案 0 :(得分:3)
如果您正在阅读二进制文件,NUL字符可能会出现在文件的任何位置。
因此,使用像sprintf
和strlen
这样的字符串函数是一个坏主意。
如果您确实需要使用第二个缓冲区(buffer
),则可以使用memcpy
。
您也可以直接读入r.payload(如果r.payload已经分配了足够的大小)。
您正在寻找fread
二进制文件。
fread
的返回值告诉您在缓冲区中读取了多少字节。
您也可以考虑再次致电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;
}
答案 1 :(得分:0)
不,sprintf未正确完成。它容易出现缓冲区溢出,这是一个非常严重的安全问题。
我会考虑将文件作为例如1024字节的块而不是逐行的,所以我会用fread调用替换fgets调用。
为什么要打开文件两次?显然要获得它的大小,但你只能打开它一次并跳回文件的开头。并且,您没有使用您阅读的尺寸。
答案 2 :(得分:0)
是二进制文件还是文本文件? fgets()假设您正在读取文本文件 - 它在换行符处停止 - 但您说它是一个二进制文件并用&#34; rb&#34;打开它。 (实际上,第一次使用&#34; rt&#34;打开它时,我认为这是一个错字)。
IMO你永远不应该使用sprintf。写入缓冲区的字符数取决于传入的参数,在这种情况下,如果没有&#39; \ 0&#39;在缓冲区中,你无法预测将多少字节复制到r.payload,并且很有可能会溢出该缓冲区。
我认为sprintf()将是第一个要解决的问题。使用memcpy(),您可以准确地告诉它要复制多少字节。