从 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 字符可能会出现在文件中的任何位置。
因此,使用像 sprintf
和 strlen
这样的字符串函数不是一个好主意。
如果你真的需要使用第二个缓冲区 (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(),你可以准确地告诉它要复制多少字节。
我目前正在做一个项目,我必须从二进制文件中读取并通过套接字发送它,但我很难尝试发送整个文件。
这是我到目前为止写的:
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 字符可能会出现在文件中的任何位置。
因此,使用像 sprintf
和 strlen
这样的字符串函数不是一个好主意。
如果你真的需要使用第二个缓冲区 (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(),你可以准确地告诉它要复制多少字节。