【问题标题】:std::string.length() not counting \r\nstd::string.length() 不计算 \r\n
【发布时间】:2017-08-03 13:08:03
【问题描述】:

我正在使用 C++ 开发 HTML 表单处理器,主要是作为学习经验。我有一个小的输出缓冲区类允许我发送Content-Length 标头。在我尝试读入和输出模板文件之前,它工作正常。它在 Windows 系统上,所以这些行当然以\r\n 结尾,但是当我在缓冲区字符串上使用length() 方法时,它没有计算两个字符,并且我的Content-Length 结束了。我尝试使用ios::binary 和不使用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

【问题讨论】:

  • 使用ios::binary 应该有所作为。
  • 你能展示一下你是如何以二进制模式读取文件的吗?
  • 这就是您打开文件的方式。您如何读取文件?
  • 您没有以二进制模式打开输出文件。

标签: c++ windows text-files stdstring


【解决方案1】:

Windows stdout 处于二进制模式

正如我上面的编辑和 cmets 所指出的,问题根本不在于string.length(),而在于 Windows 在发送到stdout 时将所有\n 转换为\r\n。它甚至可以使用现有的\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 和其他所有人的帮助,感谢您继续在我真正需要做的事情上打败我,直到它最终卡住。

【讨论】:

    猜你喜欢
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 1970-01-01
    • 2020-07-23
    • 1970-01-01
    相关资源
    最近更新 更多