How to add a new data to existing Binary file without erase the previous data?

Hi there, I save my meshes data using Binary format. I can save and load using Binary format. But I saw there a little issue in saving step. I can save then load it back. But when I launch the game and I add new variables into MeshData” class and I save it then when I load and I see that my previous data erased in the saved file. Because the file is overwriting into existing file.

SHORTLY:

Saving the File Without Deleting What’s Already There. I do not want to overwrite the whole file. I just want to add a new line/data into existing file without erase the previous data. How to add a new data into existing Binary file?

Code to SAVE and LOAD Mesh Data:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

[System.Serializable]
public class MeshData
{
    public List<float> vertices;
    public List<float> uvs;
    public List<float> normals;
    public List<int> triangles;
}

[System.Serializable]
public class MeshDatabase
{
    public MeshData[] meshDatas;
}

public class GetMeshData : MonoBehaviour
{
    public MeshData[] meshDatas;
    public MeshDatabase meshDatabase;

    public BinaryFormatter binaryFormatter;
    public FileStream fileStream;
  
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.S))
        {
            Save();
            Debug.Log("SAVED");
        }

        if (Input.GetKeyDown(KeyCode.L))
        {
            Load();
            Debug.Log("LOADED");
        }
    }

    public void Save()
    {
        binaryFormatter = new BinaryFormatter();
        fileStream = File.Create(Application.dataPath + "/StreamingAssets/Mesh.dat");
        binaryFormatter.Serialize(fileStream, meshDatabase);
        fileStream.Close();
    }

    public void Load()
    {
        if (File.Exists(Application.dataPath + "/StreamingAssets/Data.dat"))
        {
            binaryFormatter = new BinaryFormatter();
            fileStream = File.Open(Application.dataPath + "/StreamingAssets/Mesh.dat", FileMode.Open);
            meshDatabase = (MeshDatabase)binaryFormatter.Deserialize(fileStream);
            fileStream.Close();
        }
    }
}

PLEASE EXPLAIN AS CODE!!! THANKS.

That kind of binary stream is lacking any kind of formatting, so you need to preserve the previous shape of the datagram if you want to read it.

However, you really shouldn’t be using this format:

Don’t use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

If you insist on using it then you need to implement your own versioning system, so that you write (perhaps) a version integer or string out that lets your code read it with the correct shape data.

This also means you must maintain separate structures for every possible previous version of the data structure you wish to support reaching back in time.

Seriously, just use JSON.

2 Likes

Thanks for respond Kurt. I did not know Binary stream was a secure. But I saw at this video tutorial

that Binary is a most secure. Nobody can read the binary file because it is converting to unreadable state. And also I took a look at Binary file and I could not read because of encryption. Even I saw that MINECRAFT use Binary format to save data. Still I did not understand. Also I wanted to learn use JSON to save and load data for mySQL database. But my game is not an online for right now. I think to add online later and I think that there a little things to do before to use the JSON. I will pay attention to your advice.

So I have a few question.

1) can I add a new line into JSON file without erasing the previous data/lines? Or I can not do that with this format too?
2) Is there not another easy way to add a new line without lost the previous data? Or there is not, then I need to keep the previous data then, add a new data and save these whole data again into file, Yes, like this ?

Why you want to do that?You can make all your save data like one c# object and then,then replace values you need and save it again.

1 Like
string filename = Application.dataPath + "/StreamingAssets/Mesh.dat";
if (File.Exists(filename))
    fileStream = File.OpenWrite(filename);
else
    fileStream = File.Create....

in your code every time you press save you create a new file…

1 Like

You clearly have not met any of the 12-year-olds who regularly break security by reading binary files. There is nothing different from a binary file and a JSON file. If you doubt me, just use the xxd utility (a Posix tool) and hex dump your binary and there will be all your data.

There is. You can write it to separate files. You can write it as separate chunks end to end to end. But if you change any of the underlying structure of the chunks, it won’t be trivial to read back in.

This is just how unstructured binary data works. It’s just a bag of bytes without any clue as to what is what. The “clue” comes in the shape of your program’s structure, and when you change it, well, it no longer matches!

1 Like

Thanks for respond, yeah I forgot to check if exist then use openwrite operation, Thanks

1 Like

there arent many of those 12 years old doing it, especially not for simple savegame editing. those can do it, deserve to do it but binary savegame is the fastest and easiest way as there is no parsing, also easiest to encrypt if you are worried. json xml are simply readable to anyone with a notepad and slow af. this is just a microsoft crap and we are surprised why do we need 16 cores 5ghz pc-s that should run on a 200mhz celeron

2 Likes

There is. You can write it to separate files. You can write it as separate chunks end to end to end. But if you change any of the underlying structure of the chunks, it won’t be trivial to read back in.

This is just how unstructured binary data works. It’s just a bag of bytes without any clue as to what is what. The “clue” comes in the shape of your program’s structure, and when you change it, well, it no longer matches![/QUOTE]

Oh, I did not know about 12 years old child hacked binary files and succeed to read binary file. This was a really import information, thanks for gave a such an important info. I don’t doubt. Then I need to use JSON later.

You said that JSON is more secure, right? If I am wrong, then you say me, I understood that JSON is more secure than Binary, am I right?

You mean by to save in different files? Create different files for each chunks and load it back and change something or add then save it, is it? And still this means that I need to load all data variables back then save these again?

I divide save files. I load variables back with variables and I adding or changing something then I need to save all previous and new variables into a file, right?

Below I load variables back into as variable and (removing or adding new variables) and I saving these whole. Is it optimized or efficient way to do, or not? Did you mean like this?

    public MyData[] myDatas;
    public void Load()
    {
        if (File.Exists(Application.dataPath + "/StreamingAssets/Data.dat"))
        {
            binaryFormatter = new BinaryFormatter();
            fileStream = File.Open(Application.dataPath + "/StreamingAssets/Data.dat", FileMode.Open);
            myDatabase = (MyDatabase)binaryFormatter.Deserialize(fileStream);
            fileStream.Close();
     
            myDatas = new MyData[myDatas.Length];
            for (int i = 0; i < myDatas.Length; i++)
            {
                myDatas[i] = myDatas[i];
            }
        }
    }

Did you mean like this?

I said nothing about security of any format. There is zero security conferred by the format of the data.

If data is on an untrusted computer (eg, one you don’t control), it is not secure.

Therefore, why make life difficult for yourself with binary data? Your costs go up, your security does not change.

I got it.

But my last example is right? Can you reply please.

I cannot run your code. You can run your code. Devise a quick experiment / test and see if it works!

1 Like

So much misconception is going around in this thread… some of my thoughts around the subject:

I use JSON save file in development but binary in build. The reason is I can check on what I’m doing easily, but I don’t need to pay the endless string-processing price in build.
Best of both worlds. The only price is that I can’t test my dev saves in builds. (I can switch to binary read in dev though)

The binary formatter contains flaws which makes it unsafe to process data coming from outside sources. If you’re on a server where you are processing data from the clients, you need to forget its existence. If you’re developing a desktop application and you save and load files on the local computer, you shouldn’t care. Nothing outside comes in unless the user deliberately replaces a save file with some arbitrary file. The attack vector here is very weak.

ps: With that said, I myself also switched to BinaryWriter just because I’m maintaining code for multiple uses and if the code ends up on the server side, it shouldn’t cause a problem.

In both cases your only right way is to load the data in, make it object format, insert your new data and overwrite the file.
You do not “insert” data into a file. You can append text files though, but data-structure-wise it’s not an option.

1 Like

I made like this. I load back my data into variables and I overwrite these with new and previous data into file

CODE to load back data as variables, is it right?

    public MyData[] myDatas;
    public void Load()
    {
        if (File.Exists(Application.dataPath + "/StreamingAssets/Data.dat"))
        {
            binaryFormatter = new BinaryFormatter();
            fileStream = File.Open(Application.dataPath + "/StreamingAssets/Data.dat", FileMode.Open);
            myDatabase = (MyDatabase)binaryFormatter.Deserialize(fileStream);
            fileStream.Close();
  
            myDatas = new MyData[myDatas.Length];
            for (int i = 0; i < myDatas.Length; i++)
            {
                myDatas[i] = myDatas[i];
            }
        }
    }

But another way. If there are a lot of data and it takes a lot time to load a huge data. I mean with a “Huge Data” like (mesh vertices, triangles, uvs, position and rotation). My data is like this. And I need to divide to different files for not to take a long time to load and save it. And another question is, if there are trillion saved files in the game folder then it will be take a long time to search from these trillion saved files? I hope to explained well my question.

I used to insert data into file using File.Append but then I could not load it, and it gave me an error, even did not load

Just follow this tutorial, this way of saving is easy and much more secure.If you create your save file as one object of all data you can then find data you want replace in list and save it all again.

    CreateSaveObjects();
            void CreateSaveObjects()
            {
                //Get all new data from variables in Save method
                var objectForSave = new PlanetObject(planetNumber, planetSize, planetType, planetGoal, totalMinerals, remainingMaterialsList.Count, saveList, questList,Galaxy.GetPlanetObject(Galaxy.planetToLoad).planetPosition,planetStatus);
                //Get all old data
                var planetList = Galaxy.GetLoadedPlanetObjectList();
                var clusterPosition = Galaxy.GetClusterObject(Galaxy.clusterToLoad).clusterPosition;
                var clusterList = Galaxy.GetLoadedClusterObjectList();
                var galaxyNumber = Galaxy.GetGalaxyObject().galaxyNumber;
                //Find and replace old object with new object in loaded list
                planetList[planetList.FindIndex(ind => ind.planetNumber.Equals(Galaxy.planetToLoad))] = objectForSave;
                cO = new ClusterObject(Galaxy.clusterToLoad, planetList, clusterPosition);
                //Find and replace old object with new object in loaded list
                clusterList[clusterList.FindIndex(ind => ind.clusterNumber.Equals(Galaxy.clusterToLoad))] = cO;
                gO = new GalaxyObject(clusterList, galaxyNumber);
                //Save object with replaced data
                SaveManager.SaveGalaxy(this, galaxyNumber);
           
            }
 public static void SaveGalaxy(TerrainManager gO, int clusterNumber)
        {

            string planetDirectory = StaticRuntime.GetApplicationPath() + "/save/galaxy/";
            if (!Directory.Exists(planetDirectory))
            {

                Directory.CreateDirectory(planetDirectory);
            }

            string saveGameFileName = clusterNumber.ToString();
            string saveGamePath = StaticRuntime.GetApplicationPath() + "/save/galaxy/" + saveGameFileName + ".pgpro";


            if (File.Exists(saveGamePath))
            {
                File.Delete(saveGamePath);
            }
            BinaryFormatter formatter = new BinaryFormatter();
            FileStream stream = new FileStream(saveGamePath, FileMode.Create);
            GameData data = new GameData(gO);
            formatter.Serialize(stream, data);
            stream.Close();    
        }
    [System.Serializable]
    public class GameData
    {

     
 
 
     
        public GalaxyObject _gO;

        //SaveManager
        
  
        public GameData(TerrainManager terrainManager)
        {     

            _gO = terrainManager.gO;
        }         
  
    }
1 Like

I will try this code, if I have problems then I will let you know here in this post. But Brackeys save and load system is similar like mine. But your code is not look like in the video. I think this is a scriptable object saving type which you gave in the code. I will try this code.

i edited my code first part so make it more readable

1 Like

In my code i am using c# objects Galaxy is constructed from List of Cluster objects and Cluster object is constructed from list of Planet objects and Planet object is constructed from other objects… point is if i save i only save Galaxy object since it is in top of this hierarchy, all what is inside of this object is saved.

7105552--847312--objects.png

1 Like