std::string.length() 不算 \r\n
std::string.length() not counting \r\n
我正在使用 C++ 开发 HTML 表单处理器,主要是作为一种学习经验。我有一个小输出缓冲区 class 允许我发送 Content-Length
header。在我尝试读入和输出模板文件之前,它工作正常。它在 Windows 系统上,所以这些行当然以 \r\n
结束,但是当我在我的缓冲区字符串上使用 length()
方法时,它不计算两个字符,我的 Content-Length
结束了。我尝试使用和不使用 ios::binary
读取文件,但没有任何区别。
[编辑]
好的,抱歉,这是重现问题的最少代码:
#include <iostream>
#include <fstream>
#include <sys/stat.h>
using namespace std;
size_t fileSize(const char* filename) {
struct stat st;
if(stat(filename, &st) != 0) return 0;
return st.st_size;
}
int main() {
char fName[] = "testack.html";
char oName[] = "testout.txt";
int _size;
char *_content;
ifstream inFile;
inFile.open(fName, ios::binary);
if (inFile.good()) {
_size = fileSize(fName);
_content = new char[_size + 1];
inFile.read(_content, _size);
_content[_size] = 0;
}
ofstream os(oName);
os << _content;
return 0;
}
这里是测试文件:
<HTML><BODY>Hello World!</BODY></HTML>
那是 38 个字节,Windows 我的程序和每个人都同意,我最终在 testout.txt
中得到 38 个字节 现在,如果我添加一个换行符:
<HTML>
<BODY>Hello World!</BODY></HTML>
Windows 说它是 40 个字节(如我所料),我的程序读取 40 个字节,最后我在输出文件中得到 41 个字节。第二个换行符:
<HTML>
<BODY>
Hello World!</BODY></HTML>
Windows 表示 42 个字节,我的程序读取 42 个字节,最后我在输出文件中得到 44 个字节。因此,当我将它输出到文件或 stdout
时,似乎每个换行符都添加了一个额外的字节。在这一点上我完全糊涂了。有什么想法吗?
[编辑]
而且,通过更多的测试,我发现每行都添加了一个额外的 \r,因此我有,例如:
<HTML>\r\r\n
Windows stdout
二进制模式
如我上面的编辑和评论所示,问题根本不在于 string.length()
,而是 Windows 在发送时将所有 \n
转换为 \r\n
至 stdout
。它甚至对现有的 \r\n
序列执行此操作,将它们变成 \r\r\n
。谢谢你,微软,你总是比我更清楚我真正想做什么。
我的第一个解决方案,在输出之前将所有 \r\n
转换为 \n
(这样当 Windows 将它们转换回 \r\n
时字节数将是正确的)这真的不是一个理想的解决方案,因为它只处理正在读取和输出的文件,而程序直接输出的任何内容都会再次导致字节计数关闭。当然,我可以直接将 \r\n
附加到我的所有输出(只是将其剥离,然后让 Windows 放回去),但这似乎有点……笨拙。经过一夜安眠和更多的思考和阅读之后,我决定强迫 Windows 不干涉我的字节是更好的解决方案——将 stdout
更改为二进制模式。
但是,BoundaryImposition 链接到的 question 没有我需要的所有信息。因此,经过大量谷歌搜索和阅读后,这里为后代提供了我确定的完整解决方案:
#if defined(_WIN32) || defined(_WIN64)
#include <io.h>
#include <fcntl.h>
#endif
int main() {
#if defined(_WIN32) || defined(_WIN64)
setmode(fileno(stdout), O_BINARY);
#endif
}
感谢 BoundaryImposition 和其他所有人的帮助,感谢你们继续用我真正需要做的事情来打败我,直到它最终卡住。
我正在使用 C++ 开发 HTML 表单处理器,主要是作为一种学习经验。我有一个小输出缓冲区 class 允许我发送 Content-Length
header。在我尝试读入和输出模板文件之前,它工作正常。它在 Windows 系统上,所以这些行当然以 \r\n
结束,但是当我在我的缓冲区字符串上使用 length()
方法时,它不计算两个字符,我的 Content-Length
结束了。我尝试使用和不使用 ios::binary
读取文件,但没有任何区别。
[编辑]
好的,抱歉,这是重现问题的最少代码:
#include <iostream>
#include <fstream>
#include <sys/stat.h>
using namespace std;
size_t fileSize(const char* filename) {
struct stat st;
if(stat(filename, &st) != 0) return 0;
return st.st_size;
}
int main() {
char fName[] = "testack.html";
char oName[] = "testout.txt";
int _size;
char *_content;
ifstream inFile;
inFile.open(fName, ios::binary);
if (inFile.good()) {
_size = fileSize(fName);
_content = new char[_size + 1];
inFile.read(_content, _size);
_content[_size] = 0;
}
ofstream os(oName);
os << _content;
return 0;
}
这里是测试文件:
<HTML><BODY>Hello World!</BODY></HTML>
那是 38 个字节,Windows 我的程序和每个人都同意,我最终在 testout.txt
中得到 38 个字节 现在,如果我添加一个换行符:
<HTML>
<BODY>Hello World!</BODY></HTML>
Windows 说它是 40 个字节(如我所料),我的程序读取 40 个字节,最后我在输出文件中得到 41 个字节。第二个换行符:
<HTML>
<BODY>
Hello World!</BODY></HTML>
Windows 表示 42 个字节,我的程序读取 42 个字节,最后我在输出文件中得到 44 个字节。因此,当我将它输出到文件或 stdout
时,似乎每个换行符都添加了一个额外的字节。在这一点上我完全糊涂了。有什么想法吗?
[编辑]
而且,通过更多的测试,我发现每行都添加了一个额外的 \r,因此我有,例如:
<HTML>\r\r\n
Windows stdout
二进制模式
如我上面的编辑和评论所示,问题根本不在于 string.length()
,而是 Windows 在发送时将所有 \n
转换为 \r\n
至 stdout
。它甚至对现有的 \r\n
序列执行此操作,将它们变成 \r\r\n
。谢谢你,微软,你总是比我更清楚我真正想做什么。
我的第一个解决方案,在输出之前将所有 \r\n
转换为 \n
(这样当 Windows 将它们转换回 \r\n
时字节数将是正确的)这真的不是一个理想的解决方案,因为它只处理正在读取和输出的文件,而程序直接输出的任何内容都会再次导致字节计数关闭。当然,我可以直接将 \r\n
附加到我的所有输出(只是将其剥离,然后让 Windows 放回去),但这似乎有点……笨拙。经过一夜安眠和更多的思考和阅读之后,我决定强迫 Windows 不干涉我的字节是更好的解决方案——将 stdout
更改为二进制模式。
但是,BoundaryImposition 链接到的 question 没有我需要的所有信息。因此,经过大量谷歌搜索和阅读后,这里为后代提供了我确定的完整解决方案:
#if defined(_WIN32) || defined(_WIN64)
#include <io.h>
#include <fcntl.h>
#endif
int main() {
#if defined(_WIN32) || defined(_WIN64)
setmode(fileno(stdout), O_BINARY);
#endif
}
感谢 BoundaryImposition 和其他所有人的帮助,感谢你们继续用我真正需要做的事情来打败我,直到它最终卡住。