13

I need to read a jpg file to a string. I want to upload this file to our server, I just find out that the API requires a string as the data of this pic. I followed the suggestions in a former question I've asked 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;
}

Why it stops at 60? It's a strange character at 60, and what should I do to read the jpg to a string?

UPDATE

Almost there, but after using the suggested method, when I rewrite the string to the output file, it distorted. Find out that I should also specify that the ofstream is in binary mode by ofstream::binary. Done!

By the way what's the difference between ifstream::binary & ios::binary, is there any abbreviation for ofstream::binary?

Community
  • 1
  • 1
Joey.Z
  • 3,450
  • 4
  • 30
  • 59
  • 2
    There is no difference between `ifstream::binary` and `ios::binary`, nor even `ofstream::binary`. `binary` is defined in the `ios_base` class, which is the root of all the iostream classes. `ios` is a typedef for `basic_ios`, which is a class that falls between `ios_base` and `istream`/`ostream` in the hierarchy. I tend to use that because it's easy to type. You can use `ios::binary` for both `ifstream` and `ofstream`. You could even use `ifstream::binary` for `ofstream`, and vice versa. – Benjamin Lindley Jul 11 '13 at 05:22

3 Answers3

24

Open the file in binary mode, otherwise it will have funny behavior, and it will handle certain non-text characters in inappropriate ways, at least on Windows.

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

Also, instead of a while loop, you can just read the whole file in one shot:

ostrm << fin.rdbuf();
Benjamin Lindley
  • 95,516
  • 8
  • 172
  • 256
10

You shouldn't read the file to a string because it is legal for a jpg to contain values that are 0. However in a string, the value 0 has a special meaning (it's the end of string indicator aka \0). You should instead read the file into a vector. You can do this easily like so:

#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;
}
Borgleader
  • 15,349
  • 5
  • 42
  • 59
  • 1
    Although a C style string can't contain a `\0`, an `std::string` can (though you're basically right -- a `std::string` really isn't the right choice for binary data). – Jerry Coffin Jul 11 '13 at 04:08
  • @JerryCoffin But the api required a string:`const string &data: the raw data of the photo to be uploaded`. – Joey.Z Jul 11 '13 at 04:09
  • @zoujyjs I edited the code sample to include how to initialize the string. It works the same way as the vector. – Borgleader Jul 11 '13 at 04:11
  • @zoujyjs: you may not have a choice, and if so, such is life. Still something to keep in mind for the future (at least in my opinion). – Jerry Coffin Jul 11 '13 at 04:16
6

Try opening the file in binary mode:

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

At a guess, you were probably trying to read the file on Windows and the 61st character was probably 0x26 -- a control-Z, which (on Windows) will be treated as marking the end of the file.

As far as how to best do the reading, you end up with a choice between simplicity and speed, as demonstrated in a previous answer.

Community
  • 1
  • 1
Jerry Coffin
  • 437,173
  • 71
  • 570
  • 1,035