简体   繁体   中英

How to serialize a list of objects with JSON

I'm developing a software to manage my collection of coins. I need to export the content of a list of objects in a JSON file but I encounter this error everytime I want to display the coins that are actually inside the database:

Additional text encountered after finished reading JSON content: [. Path '', line 1, position 109.

Here's where everything should happen:

List<Coin> coins = new List<Coin>();

public bool AddACoin (int ID, String coinName, String coinNation, String coinStatus, int coinYear, int quantity, float value)
{
    var jsonSerializer = new JsonSerializer();

    using (StreamWriter streamWriter = new StreamWriter(path, true))
    using (JsonWriter jsonWriter = new JsonTextWriter(streamWriter))
    {
        coins.Add(new Coin(ID, coinName, coinNation, coinStatus, coinYear, quantity, value));
        jsonSerializer.Serialize(jsonWriter, coins.ToList());
    }

    return true;
}

The output is stored inside different blocks of square brackets. I've a block for every object inserted. Instead I should have every object inside a unique block of square brackets. Thanks in advance.

EDIT: Here's the content of the JSON file

[{"ID":0,"coinName":"1 Euro","coinNation":"Ita","coinStatus":"FdC","coinYear":2005,"quantity":1,"value":4.7}][{"ID":0,"coinName":"1 Euro","coinNation":"Ita","coinStatus":"FdC","coinYear":2005,"quantity":1,"value":4.7},{"ID":1,"coinName":"2 Euro","coinNation":"Bel","coinStatus":"FdC","coinYear":2004,"quantity":1,"value":30.0}]

As I said, everything should be inside a unique block of square brackets.

I think that I've just found the solution to my problem and I'm going to share it with you. I've changed some lines and now I have:

public bool AddACoin (int ID, String coinName, String coinNation, String coinStatus, int coinYear, int quantity, float value)
    {
        var jsonSerializer = new JsonSerializer();

        using (StreamReader streamReader = new StreamReader(path, true))
        {
            string json = streamReader.ReadToEnd();
            coins = JsonConvert.DeserializeObject<List<Coin>>(json);
            coins.Add(new Coin(ID, coinName, coinNation, coinStatus, coinYear, quantity, value));
            string newJson = JsonConvert.SerializeObject(coins);
            streamReader.Close();
            File.WriteAllText(path, newJson);
        }
            return true;
    }

If I'm thinking correctly, doing this causes the program to read until it reaches EOF and then, after serializing/deserializing the list, appends the new object. At the moment this seems to works fine.

I recommend you to use NewtonsoftJSON (you can install it via NuGet), clear json file every time you adding new coin, there are coins manager sample for you:

public class CoinsManager
{
    public List<Coin> Coins { get; set; }

    public string FilePath { get; set; }

    public CoinsManager(string filePath)
    {
        FilePath = filePath;
        Coins = new List<Coin>();
    }

    public void LoadCoins()
    {
        if (File.Exists(FilePath))
        {
            //If file exists, but empty, save empty settings to it
            if (new FileInfo(FilePath).Length == 0)
            {
                SaveSettings();
            }
            else
            {
                //Read json from file
                using (StreamReader r = new StreamReader(FilePath))
                {
                    string json = r.ReadToEnd();
                    //Convert json to list
                    Coins = JsonConvert.DeserializeObject<List<Coin>>(json);
                }
            }
        }
        else
        {
            //Create file
            File.Create(FilePath).Close();

            //Wait for filesystem to create file
            while (!File.Exists(FilePath))
            {
                System.Threading.Thread.Sleep(100);
            }

            //Save empty settings to file
            SaveSettings();
        }
    }

    public void SaveSettings()
    {
        string json = JsonConvert.SerializeObject(Coins);

        File.WriteAllText(FilePath, json);
    }

    //Can save or update passed coin
    public void SaveCoin(Coin coin)
    {
        //Select old coin
        var oldCoin = Coins.Where(c => c.ID == coin.ID).FirstOrDefault();

        //If there was no old coin, get last existing coin id, or zero if Coins list is empty
        if (oldCoin == null)
        {
            int lastId;
            if (Coins.Count != 0)
                lastId = Coins.Count - 1;
            else
                lastId = 0;

            coin.ID = lastId + 1;
            Coins.Add(coin);
        }
        else
        {
            int index = Coins.IndexOf(oldCoin);
            Coins[index] = coin;
        }
    }

    public void DeleteCoin(Coin coin)
    {
        Coins.RemoveAll(c => c.ID == coin.Id);
    }
}

and it's usage:

    CoinsManager coinsManager = new CoinsManager("coinsStorage.json");
    coinsManager.LoadCoins();
    coinsManager.SaveCoin(new Coin {
    ...
    });
    coinsManager.SaveSettings();

if i understand correct you just need to change this row:

StreamWriter streamWriter = new StreamWriter(path, true);

to this one:

StreamWriter streamWriter = new StreamWriter(path, false);

your problem is that you always add to the file new json with all the list instead of just writing the list.

Because you work with file you need and you want to append your only option is to read the file then add elements and write it again.

You can read it when application start and menage it like it seems you do becouse your list is global.

Or you can read it right before you want to write the file.

In any one of this cases you need to add the fix I wrote.

You can use this for read the json o your list:

string myJsonString = File.ReadAllText(path);
coins = JsonConvert.DeserializeObject<List<Coin>>(myJsonString);

here is full function:

public bool AddACoin (int ID, String coinName, String coinNation, String coinStatus, int coinYear, int quantity, float value)
{
    var jsonSerializer = new JsonSerializer();

    using (StreamWriter streamWriter = new StreamWriter(path, false))
    using (JsonWriter jsonWriter = new JsonTextWriter(streamWriter))
    {
        string myJsonString = File.ReadAllText(path);
        coins = JsonConvert.DeserializeObject<List<Coin>>(myJsonString);
        coins.Add(new Coin(ID, coinName, coinNation, coinStatus, coinYear, quantity, value));
        jsonSerializer.Serialize(jsonWriter, coins.ToList());
    }

    return true;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM