locked
How can I format a proper json string to a text file and add a empty line between each string ? RRS feed

  • Question

  • This is how I'm using the json :

    Using ToJson

    public void Save()
        {
            SaveObject saveObject = new SaveObject();
            for (int i = 0; i < objectsToSave.Count; i++)
            {
                var x = objectsToSave[i].GetComponents<Component>();
                var y = x.Where(component => component is IStateQuery).ToList();
                List<KeyToValue> myObjects = new List<KeyToValue>();
                foreach(var z in y)
                {
                    var w = z as IStateQuery;
                    myObjects.Add(new KeyToValue(w.UniqueId.ToString(), w.GetState()));
                    
                }
                saveObject.position = objectsToSave[i].position;
                saveObject.scaling = objectsToSave[i].localScale;
                saveObject.rotation = objectsToSave[i].rotation;
    
                saveObject.objects = myObjects;
    
    
                string json = JsonUtility.ToJson(saveObject);
    
                SaveSystem.Save(json);
            }
        }


    Then saving the string to a text file :

    public static void Save(string saveString)
        {
            File.AppendAllText(SAVE_FOLDER + "/" + "savegame.txt", saveString + Environment.NewLine + Environment.NewLine);
        }

    But I have some problems with the AppendAllText

    If I'm using only once with the Environment.NewLine it will not add a line between the saveString's so the text saved file content will be like this :

    {"objects":[{"Key":"367f6ac2-6fd3-4c99-91e5-cc335a104ac4","Value":"{\"s1\":false}"}],"instanceID":0,"position":{"x":8.140000343322754,"y":0.0,"z":0.0},"scaling":{"x":1.0,"y":1.0,"z":1.0},"rotation":{"x":0.0,"y":0.0,"z":0.0,"w":1.0}}
    {"objects":[{"Key":"ecb45f8e-463c-4fe3-a436-5d836165bcce","Value":"{\"s1\":false}"}],"instanceID":0,"position":{"x":-11.229999542236329,"y":0.0,"z":8.920000076293946},"scaling":{"x":1.0,"y":1.0,"z":1.0},"rotation":{"x":0.0,"y":0.0,"z":0.0,"w":1.0}}

    And if I'm using the Environment.NewLine twice then the format in the text file will be with a empty line between the strings but it also will add empty line at the bottom and I don't want it to add empty line at the bottom.

    {"objects":[{"Key":"367f6ac2-6fd3-4c99-91e5-cc335a104ac4","Value":"{\"s1\":false}"}],"instanceID":0,"position":{"x":8.140000343322754,"y":0.0,"z":0.0},"scaling":{"x":1.0,"y":1.0,"z":1.0},"rotation":{"x":0.0,"y":0.0,"z":0.0,"w":1.0}}

    {"objects":[{"Key":"ecb45f8e-463c-4fe3-a436-5d836165bcce","Value":"{\"s1\":false}"}],"instanceID":0,"position":{"x":-11.229999542236329,"y":0.0,"z":8.920000076293946},"scaling":{"x":1.0,"y":1.0,"z":1.0},"rotation":{"x":0.0,"y":0.0,"z":0.0,"w":1.0}}

    The second problem is how to format the content in the text file to be in a proper json format ?

    Instead 

    {} {}

    It should be something like :

    [
       {},
       {}
    ]



    danieli

    Saturday, October 3, 2020 7:09 AM

Answers

  • I suggest this:

    public static void Save(string saveString)
    {
        string fileName = Path.Combine(SAVE_FOLDER, "savegame.txt")
        bool addingToExistingFile = File.Exists(fileName) && new FileInfo(fileName).Length > 0
        string textToPrepend = addingToExistingFile ? Environment.NewLine : string.Empty;
        File.AppendAllText(fileName, textToPrepend + saveString + Environment.NewLine);
    }

    In this way, you only construct the filename once, and you only do a single AppendText, which is a costly operation.

    • Marked as answer by chocolade Saturday, October 3, 2020 9:49 AM
    Saturday, October 3, 2020 9:29 AM

All replies

  • Starting with the first question, which I'll rephrase as "how to append a separation line between two entries in the file, but not add it at the end". If you look closely at the sentence, you will notice that it is state-sensitive, i.e., the operation that you perform depends on whether you are writing an intermediate entry or it is the last entry. To know which is the case, you could use a boolean in your code to indicate if you are in the last pass or not. Or, alternatively, within the Save routine first examine the file to see if it already has content. If it does, you write a newline and then you write your text followed by another newline. If it is empty, you omit writing the first newline. If you don't know how to check if the file is empty, please ask here and we shall write some sample code for you.

    Your second question is much more complex to solve. You see, in order to format json nin a "pretty" way, it is necessary to understand the structure of the json and the meaning of each part. You could include in your program a json parser, but it would be overkill to first serialize data into json only to immediately take the serialized data and parse it to reformat it and then re-serialize in a different format, which would require a second serializer capable of applying the right format. You might as well just use this second serializer in the first place to serialize in the proper format.

    In other words, instead of just calling JsonUtility.ToJson, you need to use a json serializer that has the ability to generate formatted json. For instance, you could use the serializer in System.Text.Json and apply the property WriteIndented. Other serializers may provide similar functionality; it's just a matter of reading their documentation and setting the appropriate properties.

    Saturday, October 3, 2020 8:07 AM
  • Should I check if the file is empty like this ?

    public static void Save(string saveString)
        {
            File.AppendAllText(SAVE_FOLDER + "/" + "savegame.txt", saveString + Environment.NewLine);
    
            if (new FileInfo(SAVE_FOLDER + "/" + "savegame.txt").Length == 0)
            {
    
            }
        }
    And then how the code should be ?



    danieli

    Saturday, October 3, 2020 8:13 AM
  • I suggest this:

    public static void Save(string saveString)
    {
        string fileName = Path.Combine(SAVE_FOLDER, "savegame.txt")
        bool addingToExistingFile = File.Exists(fileName) && new FileInfo(fileName).Length > 0
        string textToPrepend = addingToExistingFile ? Environment.NewLine : string.Empty;
        File.AppendAllText(fileName, textToPrepend + saveString + Environment.NewLine);
    }

    In this way, you only construct the filename once, and you only do a single AppendText, which is a costly operation.

    • Marked as answer by chocolade Saturday, October 3, 2020 9:49 AM
    Saturday, October 3, 2020 9:29 AM