json c++

Started by
11 comments, last by Misantes 9 years, 6 months ago

Hey all, quick question:

I'm using jsoncpp to try to load from a json file, and despite trying to read the documentation (I'm still rather new, and sometimes documentation can go over my head), I'm a little confused still on some details.

I've gotten a bare bones test working:


std::string json_example = "{\"array\":\
                            [\"item1\",\
                            \"item2\"], \
                            \"not an array\": \
                            \"asdf\" \
    }";

    Json::Value root;
    Json::Reader reader;
    bool parsedSuccess = reader.parse(json_example, root, false);

    if(not parsedSuccess)
    {
        std::cout<<"whoops"<<std::endl;
    }

    const Json::Value array = root["array"];
    for(unsigned int index = 0; index<array.size(); ++index)
    {
        std::cout<<"Element "<<index<<" in array: "<<array[index].asString()<<std::endl;
    }

This seems to work. However, it's only reading from a string created in the code. Is there supposed to be a way to load directly from a file in the directory? I was about to try to just load a string from a file using fstream and then parse it, but I thought there's perhaps a cleaner way (hopefully within the jsoncpp code) to do this.

Anyhow, any recommendations here would be greatly appreciated. This is my first foray into reading/writing to files (I've been procrastinating learning it). I'm mostly wanting to read/write things like game options, character data, save states etc for the game. Feel free to let me know if I'm going about this the wrong way, or point me to a decent tutorial. There seems to be a lot of options out there, but little in the way of clear tutorials. I toyed with XML for a little bit before settling on json. But, I'm not rigidly set on it.

Thanks in advance for any input.

Cheers :)

Beginner here <- please take any opinions with grain of salt

Advertisement
I had a quick flip through the documentation and there appears to be an overload of Json::Reader::parse (which you are already using) which takes an std::istream as input. Doesn't that solve your problem right away?

... However, it's only reading from a string created in the code. Is there supposed to be a way to load directly from a file in the directory? I was about to try to just load a string from a file using fstream and then parse it, but I thought there's perhaps a cleaner way (hopefully within the jsoncpp code) to do this.

Directly loading files is not necessarily the "cleaner way". It requires dealing with the differences in file path syntaxes (because many libraries are multi-platform), and it requires the source to be available as a stand-alone file, of course. Think of reading from a network source, or reading of file fragments embedded in an own file format. This is not that unusual. Games often use package files to reduce the amount of single files for performance and/or maintenance purposes. Or the embedding of preview images or the color profiles in e.g. PSD files. The library should also work if the stuff is already in memory (perhaps already loaded as a blob from a package file, or received from a network socket). Maybe it should also work with fragments only (similar to XML fragments) although encoding information are not available from the fragment any more.

IMHO, the cleaner way is to give a library a generic way for reading content, and do eventual file handling (locating, opening, closing) and loading externally to that.

I had a quick flip through the documentation and there appears to be an overload of Json::Reader::parse (which you are already using) which takes an std::istream as input. Doesn't that solve your problem right away?

I saw that in the documentation. So, in addition to haegarr's comment, I'm gathering that the correct (or preferred, or easiest, what-have-you) way to go about this to load the file independently, then parse it with jsoncpp. is that right? For whatever reason (probably because I'm new tongue.png), I was under the impression that the parser would read directly from the file.


... However, it's only reading from a string created in the code. Is there supposed to be a way to load directly from a file in the directory? I was about to try to just load a string from a file using fstream and then parse it, but I thought there's perhaps a cleaner way (hopefully within the jsoncpp code) to do this.

Directly loading files is not necessarily the "cleaner way". It requires dealing with the differences in file path syntaxes (because many libraries are multi-platform), and it requires the source to be available as a stand-alone file, of course. Think of reading from a network source, or reading of file fragments embedded in an own file format. This is not that unusual. Games often use package files to reduce the amount of single files for performance and/or maintenance purposes. Or the embedding of preview images or the color profiles in e.g. PSD files. The library should also work if the stuff is already in memory (perhaps already loaded as a blob from a package file, or received from a network socket). Maybe it should also work with fragments only (similar to XML fragments) although encoding information are not available from the fragment any more.

IMHO, the cleaner way is to give a library a generic way for reading content, and do eventual file handling (locating, opening, closing) and loading externally to that.

This actually does make sense to me and in hindsight and I can see why the library is much more versatile focusing solely on parsing the information and not handling the loading of the files. Thank you for clearing that up.

Alright, that clears things up considerably for me. I have a bit of reading to do in c++/iostream/ifstream(again, I had mostly been avoiding learning to read from files. I was a bit intimidated by it, and hadn't had much of a use until now for it), and a lot of work figuring out to incorporate it into my program.

Thanks for the input, all. smile.png

Beginner here <- please take any opinions with grain of salt

You do not have to load the content yourself. You can create an std::ifstream, open the file and then pass the stream to Json::Reader::parse.

You can also wrap a block of memory into an std::istringstream (or a custom stream) and pass it to Json::Reader::parse.

You can also create a custom stream which can load directly from a network source or your custom package format and pass it directly to Json::Reader::parse.

That's the nice thing about abstraction. A stream is just a source of data until it says it has no more data. Whether the data is coming from a file, the network or some other arcane source is irrelevant for the user of the stream.

You do not have to load the content yourself. You can create an std::ifstream, open the file and then pass the stream to Json::Reader::parse.

You can also wrap a block of memory into an std::istringstream (or a custom stream) and pass it to Json::Reader::parse.

You can also create a custom stream which can load directly from a network source or your custom package format and pass it directly to Json::Reader::parse.

That's the nice thing about abstraction. A stream is just a source of data until it says it has no more data. Whether the data is coming from a file, the network or some other arcane source is irrelevant for the user of the stream.

ah, brilliant. I wasn't aware of that. Again, I'm just starting to research reading/writing files, but up until now haven't really explored the ins/outs of iostream past the standard cout/cin, and some limited fstream uses. I have some good resources to look through for the rest of the week smile.png.

I'm sure I'll have some follow-up questions down the line tongue.png but, I think I need to dig into things a little (lot) before I have anything really constructive to ask.

Beginner here <- please take any opinions with grain of salt


That's the nice thing about abstraction. A stream is just a source of data until it says it has no more data. Whether the data is coming from a file, the network or some other arcane source is irrelevant for the user of the stream.

Yep, that's the consequence from the "generic reading" mentioned above :) Although many libraries nevertheless offer various methods of input management; e.g. the FreeType library has.

Well, just for clarification for the OP: There are also caveats to be considered: The library must not be allowed to read behind the logical end of data. If a stand-alone file is opened and wrapped by a stream then there is a natural end. Giving the library a stream on a network socket, a generous memory block or a package file may allow the library to read more bytes than intended for its purpose. This should be considered, e.g. by using an appropriate stream (if exists) or implementing a wrapping stream that reports an EOF if the logical end of data is reached. Similarly, if seeking is supported, the outermost stream may have to handle an appropriate offset.


That's the nice thing about abstraction. A stream is just a source of data until it says it has no more data. Whether the data is coming from a file, the network or some other arcane source is irrelevant for the user of the stream.

Yep, that's the consequence from the "generic reading" mentioned above smile.png Although many libraries nevertheless offer various methods of input management; e.g. the FreeType library has.

Well, just for clarification for the OP: There are also caveats to be considered: The library must not be allowed to read behind the logical end of data. If a stand-alone file is opened and wrapped by a stream then there is a natural end. Giving the library a stream on a network socket, a generous memory block or a package file may allow the library to read more bytes than intended for its purpose. This should be considered, e.g. by using an appropriate stream (if exists) or implementing a wrapping stream that reports an EOF if the logical end of data is reached. Similarly, if seeking is supported, the outermost stream may have to handle an appropriate offset.

Ah, got it. If I recall correctly, I saw a reader function in the documentation for jsoncpp that had parameters for the beginning and end of the file. At the moment, my game has no networking capabilities (though, it is two player, so it's in the eventual "todo" :P), but I'll keep an eye out for the memory block size. Is this mostly an issue for performance? I could see how it could cause significant slowdown if used within the game loop with too large a memory block to read. I think for the moment, I'll pretty much be reading everything at start-up, and setting the variables within the program, and then writing everything back down to file on save.

Beginner here <- please take any opinions with grain of salt

Alright, so, I think I've a loose handle on this.

After reading about IO all evening, I've come up with this:

I had a few troubles figuring out how to access the particular...node(?) or what-have-you of the json file, but stumbled upon it eventually. But, it seems to work. I think I can figure out how to incorporate it into my program without too many issues.


std::string lineOne;
std::string lineTwo;
try 
{ 
    std::ifstream TESTFILE; 
    TESTFILE.open("test2.json", std::ios::in);

    std::getline(TESTFILE, LineOne);//unsure why these two lines are necessary. Leftover from previous IO testing
    std::getline(TESTFILE, LineTwo);//without them, the reader will return NULL values though...
    Json::Value root; 
    Json::Reader reader; 

    bool parsedSuccess = reader.parse(TESTFILE, root, false); 

    if(not parsedSuccess) 
    { 
        std::cout<<"failed, damnit"<<std::endl; 
    } 
    else 
    { 
        std::cout<<"yay"<<std::endl; 
    } 

    const Json::Value testValue(root["firstValue"]);//name of first value in my example file 
    std::cout<<"The first value is "<<testValue<<std::endl; TESTFILE.close(); 
} 
catch(std::exception X) { std::cout<<"whoops, exception"<<std::endl; } 

Though, I seriously have the damnedest time reading documentation. I guess I can understand what any particular function is kind of doing, but I seriously have a difficult time figuring out how it all fits together. Maybe that just comes with time, but right now, for me, it's like trying to understand how to speak a language just by reading a dictionary. Trial and error pretty much ended up winning out today, over actually understanding the documentation tongue.png

Anyhow, thanks again to both of you, Haegar and BitMaster, you've helped a ton! smile.png

Edit**

I had taken it out of my original example, as they were just part of my testing of various IO functions, but realized that without using std::getline() on the openfile, the JSON reader will return null values. I can't quite figure out why I'm needing to do that first. Shouldn't the reader function be able to parse that without getting the lines first?

Beginner here <- please take any opinions with grain of salt


Though, I seriously have the damnedest time reading documentation. I guess I can understand what any particular function is kind of doing, but I seriously have a difficult time figuring out how it all fits together. Maybe that just comes with time, but right now, for me, it's like trying to understand how to speak a language just by reading a dictionary. Trial and error pretty much ended up winning out today, over actually understanding the documentation

This is a reason why tutorials exist. A (good) tutorial explains how to use what in which situations, while a documentation enumerates all possibilities without regarding use cases much. Tutorials are much more suitable for learning, and documentation is good for looking up details or things learned earlier but forgotten for now.

This topic is closed to new replies.

Advertisement