使用C++将二进制文件(jpg)读取为字符串

16

我需要将一个jpg文件读取为字符串。我想上传这个文件到我们的服务器,但我发现API要求这张图片的数据为字符串。我按照之前我提出的一个问题中所建议的步骤 Upload pics to a server using c++ 进行操作。

int main() {
    ifstream fin("cloud.jpg");
    ofstream fout("test.jpg");//for testing purpose, to see if the string is a right copy
    ostringstream ostrm;

    unsigned char tmp;
    int count = 0;
    while ( fin >> tmp ) {
        ++count;//for testing purpose
        ostrm << tmp;
    }
    string data( ostrm.str() );
    cout << count << endl;//ouput 60! Definitely not the right size
    fout << string;//only 60 bytes
    return 0;
}

为什么停在60?在60有个奇怪的字符,我应该怎么样将jpg读成字符串?

更新

快了,但是用了建议的方法后,当我将字符串重写到输出文件时,它变形了。发现我还应该通过 ofstream::binary 指定 ofstream 是二进制模式。完成!

顺便问一下,ifstream::binaryios::binary 有什么区别?ofstream::binary 有没有缩写?


2
ifstream::binaryios::binary 以及 ofstream::binary 没有区别。binaryios_base 类中定义,它是所有 iostream 类的根。iosbasic_ios<char> 的 typedef,它是在层次结构中介于 ios_baseistream/ostream 之间的类。我倾向于使用它,因为它很容易输入。您可以同时用于 ifstreamofstreamios::binary。甚至可以将 ifstream::binary 用于 ofstream,反之亦然。 - Benjamin Lindley
3个回答

27

以二进制模式打开文件,否则它会表现出奇怪的行为,并且会以不合适的方式处理某些非文本字符,至少在Windows上是这样。

ifstream fin("cloud.jpg", ios::binary);

此外,你可以直接一次性读取整个文件而不是使用 while 循环:

ostrm << fin.rdbuf();

10

你不应该将文件读取到字符串中,因为JPG文件中可能包含值为0的内容。然而在字符串中,值0具有特殊含义(它是字符串结束指示符即\0)。相反,你应该将文件读取到一个向量中。你可以轻松地这样做:

#include <algorithm>
#include <iostream>
#include <fstream>
#include <vector>

int main(int argc, char* argv[])
{
    std::ifstream ifs("C:\\Users\\Borgleader\\Documents\\Rapptz.h");

    if(!ifs)
    {
        return -1;
    }

    std::vector<char> data = std::vector<char>(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());

    //If you really need it in a string you can initialize it the same way as the vector
    std::string data2 = std::string(std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>());

    std::for_each(data.begin(), data.end(), [](char c) { std::cout << c; });

    std::cin.get();
    return 0;
}

1
虽然 C 风格的字符串不能包含 \0,但 std::string 可以(尽管您基本上是正确的——对于二进制数据来说,std::string 真的不是正确的选择)。 - Jerry Coffin
1
@JerryCoffin 但是API要求一个字符串:const string &data: 要上传的照片的原始数据 - Joey.Z
@zoujyjs 我编辑了代码示例,包括如何初始化字符串。它的工作方式与向量相同。 - Borgleader
@zoujyjs:也许你没有选择的余地,如果是这样,那就是生活。但至少在我看来,这是未来需要牢记的事情。 - Jerry Coffin

6
尝试以二进制模式打开文件:
ifstream fin("cloud.jpg", std::ios::binary);

猜测您可能正在Windows上尝试读取文件,第61个字符可能是0x26 -- 一个控制-Z,在Windows上会被视为标记文件结尾。

至于如何最好地进行读取,您需要在简单和速度之间做出选择,正如以前的答案所示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接