0

I am trying to open a json file that I will be working with in C++. Code that I have used successfully before fails to open the file. I am using Visual Studio 2017 on Windows 10 Pro with JSON for Modern C++ version 3.5.0.

I have a very simple function, which is supposed to open a file as input to a json object. It appears to open the file, but aborts when writing it to the json object. Originally the file to be opened was in another directory, but I moved it into the same directory as the executable while testing...but it didn't help.

Here is the very short function that fails:

json baselineOpenAndRead(string fileName) //passed string used for filename 
{

    json baseJObject;
    cout << "we have a baseJObject" << endl;

    //ifstream inFileJSON("test_file.json");  // Making this explicit made no difference
    ifstream inFileJSON;
    inFileJSON.open("test_file.json", ifstream::in); 
    cout << "we have opened json inFileJSON" << endl; // get here


    inFileJSON >> baseJObject;
    cout << " Can direct inFileJSON into baseJObject" << endl; //never get here; the app aborts.
    inFileJSON.close();
    return baseJObject;
}

This seems basically identical to the example on the nlohmann site:

// read a JSON file
std::ifstream i("file.json");
json j;
i >> j;

I just expected this to open the json file, load it into the object, and return the object. Instead, it just quits.

Thanks for any thoughts...i.e., what am I doing wrong? (I'm going to ignore that it worked before...maybe I missed something).

--Al

As requested, here is a minimal reproducible example, but it will require nlohmann's json.hpp in order to compile:

#include <iostream>
#include <fstream>
#include "json.hpp"

using json = nlohmann::json;
using namespace std;

string fileName;
json baselineOpenAndRead(string);

int main(int argC, char *argV[])
{
    json baseJObject;

    if (argC != 2) // check to make sure proper number of arguments are given.
    {
        cout << "\n\nFilename needed...";
        exit(1); // number of arguments is wrong - exit program
    }
    else
    {
        fileName = argV[1];
        baseJObject = baselineOpenAndRead(fileName); // opens and reads the Base Line JSON file
        cout << "baseJObject returned" << endl;
    }
    return 0;
}

json baselineOpenAndRead(string fileName) // 
{
    cout << "File name: " << fileName << endl;
    json baseJObject;
    cout << "we have a baseJObject" << endl;

    ifstream inFileJSON(fileName);

    if (inFileJSON.is_open())
    {
        cout << "file open..." << endl;
        if (nlohmann::json::accept(inFileJSON))
        {
            cout << "valid json" << endl;
            try { inFileJSON >> baseJObject; }
            catch (const std::exception &e) { std::cout << e.what() << '\n'; throw; }
        }
        else
        {
            cout << "not valid json" << endl;
        }
    }
    else
    {
        cout << "file not really open" << endl;
    }
    inFileJSON >> baseJObject;
    cout << " We can echo inFileJSON into baseJObject" << endl;
    inFileJSON.close();
    return baseJObject;
}

I tested it with this json file:

{
    "people": [{
            "name": "Scott",
            "website": "stackabuse.com",
            "from": "Nebraska"
        },
        {
            "name": "Larry",
            "website": "google.com",
            "from": "Michigan"
        },
        {
            "name": "Tim",
            "website": "apple.com",
            "from": "Alabama"
        }
    ]
}

When I run this passing it the json above as data.json, I get the following output and then it quits:

./Test_json data.json
File name: data.json
we have a baseJObject
file open...
valid json
[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal

Without the try, it just quits. It never gets past inFileJSON >> baseJObject;

Another try that seems to work, but why?

OK. I tried this with the same main (the only changes are in the function):

json baselineOpenAndRead(string fileName) // 
{

    json baseJObject;
    string filePath = "../baselines/" + fileName;
    cout << "filePath: " << filePath << endl;
    ifstream inFileJSON(fileName);
    //baseJObject = json::parse(inFileJSON);
    inFileJSON >> baseJObject;
    cout << baseJObject << std::endl;
    return baseJObject;
}

This looks basically the same to me. I tried making it ifstream inFileJSON(fileName.c_str()) on both the original and in this one. The original continued to fail, this one continued to work. Sorry this is getting so long, but I can't get decent formatting out of comments... Should I just try answering my own question instead?

Al G
  • 115
  • 4
  • 10
  • After opening the file, does `inFileJSON.is_open()` return true? If not, the file was not opened. My guess is that for whatever reason (either file not opened, or some parsing error), the stream-input operator for your `json` object is throwing an exception. Since you're not catching any exceptions, the program aborts. Try attaching a debugger and enable break-on-exception. – paddy Oct 14 '19 at 04:13
  • Please provide a [mcve] with JSON file. – Thomas Sablik Oct 14 '19 at 04:13
  • Use try/catch to see errors: `try { inFileJSON >> baseJObject; } catch (const std::exception &e) { std::cout << e.what() << '\n'; throw; }` – Thomas Sablik Oct 14 '19 at 04:24
  • Thanks. The exception catch you suggested indicated that it didn't like the json file. JSONLint says it is valid; so I'm playing around. I'll try to get an example with an example json posted. – Al G Oct 14 '19 at 04:56
  • The exception could also indicate that the file could not be opened. There is no exception for this case. – Thomas Sablik Oct 14 '19 at 05:02
  • BTW. inFileJSON.is_open() does return true; so I guess my json (valid or not) is the culprit. – Al G Oct 14 '19 at 05:04

1 Answers1

0

I think I've got this. I believe my initial problem was caused by an errant ',' in one of my json test files. Subsequently, the if (inFileJSON.is_open) worked, but the if (nlohmann::json::accept(inFileJSON) was failing and causing the same (or perhaps a similar) error. I thought that I needed the c_str() for file paths outside of the executable's directory, but it doesn't seem to make a difference one way or the other. I took out the accept(), and this code seems to work consistently:

json baselineOpenAndRead(string fileName) // 
{
    json baseJObject;
    cout << "we have a baseJObject" << endl;
    string filePath = "../baselines/" + fileName;
    cout << "filePath: " << filePath << endl;
    //ifstream inFileJSON(filePath.c_str());
    ifstream inFileJSON(filePath);

    if (inFileJSON.is_open())
    {
        cout << "File is open." << endl;
        inFileJSON >> baseJObject;
        cout << baseJObject << std::endl;
        inFileJSON.close();
        return baseJObject;
    }
    else
    {
        cout << "File not open." << endl;
        exit(1);
    }
}

Thanks to everyone for your help. I appreciate it.

--Al

Al G
  • 115
  • 4
  • 10
  • It seems that I was actually having problems with files getting converted from "UTF-8 Unicode text", which opened fine, to "Non-ISO extended-ASCII text", which failed miserably (which I found running file on them from a Cygwin bash shell). My fix was to use the "Convert to UTF-8" from the Encoding drop down in Notepad++. Now how they got munged...I have no idea. Too many editors probably. --Al – Al G Oct 17 '19 at 16:22
  • Well, I may have spoken too soon. I have posted another question about the same issue: https://stackoverflow.com/questions/58566296/opening-a-json-file-giving-fits?noredirect=1#comment103452979_58566296. I had a suggestion that I was passing EOF to the parser causing the abort, but I just don't know. I get this error from the Visual Studio debugger: Unhandled exception at 0x75581932 in compareScrape.exe: Microsoft C++ exception: nlohmann::detail::parse_error at memory location 0x0117EC0C. occurred – Al G Oct 26 '19 at 02:46