我没有使用fscanf()
的经验,也没有FILE
的功能。我有正确的代码来确定客户端是否请求了现有文件(使用stat()
并确保它不是目录)。我将省略这一部分,因为它工作正常。
我的目标是使用HTTP标头(字符串)和正确读取的数据将字符串发送回客户端,我认为这些数据在某些时候必须成为字符串以与发送回的标头连接。我知道+
无效C,但为了简单起见,我想发送此信息:headerString+dataString
。
下面的代码似乎适用于文本文件,但不适用于图像。我希望单独阅读每个角色可以解决问题,但事实并非如此。当我在我的服务器上指向浏览器(Firefox)寻找图像时,它告诉我“图像(图像的名称)无法显示,因为它包含错误。”。
这是应该将文件读入httpData
的代码:
int i = 0;
FILE* file;
file = fopen(fullPath, "r");
if (file == NULL) errorMessageExit("Failed to open file");
while(!feof(file)) {
fscanf(file, "%c", &httpData[i]);
i++;
}
fclose(file);
printf("httpData = %s\n", httpData);
修改:这是我发送的内容:
char* httpResponse = malloc((strlen(httpHeader)+strlen(httpData)+1)*sizeof(char));
strcpy(httpResponse, httpHeader);
strcat(httpResponse, httpData);
printf("HTTP response = %s\n", httpResponse);
数据部分产生????对于图像,但正确的html为HTML文件。
答案 0 :(得分:1)
图片包含二进制数据。 256个不同的8位模式中的任何一个可以出现在图像中,尤其包括空字节0x00或'\0'
。在某些系统(尤其是Windows)上,您需要使用标准I / O b
调用中的字母fopen()
来区分文本文件和二进制文件(在Unix和Windows上都能正常工作)。鉴于二进制数据可以包含空字节,您不能使用strcpy()
等来复制数据块,因为str*()
函数在第一个空字节处停止复制。因此,您必须使用mem*()
函数来获取起始位置和长度,或等效函数。
应用于您的代码,使用httpData
打印二进制%s
将无法正常工作; %s
将停在第一个空字节处。由于您已使用stat()
来验证文件是否存在,因此您还拥有该文件的大小。假设您不必处理动态更改的文件,这意味着您可以将httpData
分配为正确的大小。您也可以将大小传递给阅读代码。这也意味着读取代码可以使用fread()
,编写代码可以使用fwrite()
,从而节省逐个字符的I / O.
因此,我们可能有一个功能:
int readHTTPData(const char *filename, size_t size, char *httpData)
{
FILE *fp = fopen(filename, "rb");
size_t n;
if (fp == 0)
return E_FILEOPEN;
n = fread(httpData, size, 1, fp);
fclose(fp);
if (n != 1)
return E_SHORTREAD;
fputs("httpData = ", stdout);
fwrite(httpData, size, 1, stdout);
putchar('\n');
return 0;
}
该函数在成功时返回0,并在失败时返回一些预定义的(负?)错误号。由于内存分配是在调用例程之前完成的,因此非常简单:
在原始代码中,有一个循环:
int i = 0;
...
while(!feof(file)) {
fscanf(file, "%c", &httpData[i]);
i++;
}
这个循环有很多问题:
feof()
来测试是否有更多数据需要阅读。它会报告是否已给出EOF指示 ,而不是是否。feof()
报告'false',但fscanf()
尝试读取下一个(不存在的)字符,将其添加到缓冲区(可能如a,y-umlaut,0xFF,U + 00FF,带有DIAERESIS的LATIN SMALL LETTER字母。fscanf()
相比,使用getc()
读取单个字符需要大量开销。这是一个更接近正确的代码版本,假设size
是分配给httpData
的字节数。
int i = 0;
int c;
while ((c = getc(file)) != EOF && i < size)
httpData[i++] = c;
您可以在预期时检查是否获得了EOF。请注意,fread()
代码会在fread()
函数中执行大小检查。此外,我编写参数的方式,它是一个全有或全无的命题 - 要么读取所有size
个字节,要么将所有字节视为缺失。如果您想要字节计数并且愿意容忍或处理短读取,则可以反转大小参数的顺序。你也可以检查fwrite()
的回报,如果你想确定它是全部写的,但是人们往往不太注意检查输出是否成功。 (但是,检查您是否获得了预期的输入几乎总是至关重要的 - 不要吝啬输入检查。)
在某些时候,对于纯文本数据,您需要考虑CRLF与NL行结尾。文本文件自动处理;二进制文件没有。如果要传输的数据是image/png
或类似的东西,您可能不需要担心这一点。如果你在Unix上处理text/plain
,你可能不得不担心CRLF行结尾(但我不是这方面的专家 - 我最近没有做过低级HTTP的事情(不是这个)千禧年,所以规则可能已经改变了。)