Search code examples
c#databasefilestream

C# FileStream doesn't append


I have the following C# script:

public bool Insert(QueryBuilder builder) {

        try {

            using (FileStream fs = new FileStream(GetFinalPath(builder.GetFileName()), FileMode.Append, FileAccess.Write)) {

                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(fs, builder.GetModels());

            }

            return true;

        } catch (IOException e) {
            return false;
        }

    }

When I insert one row everything is fine, as soon as I insert another row, it doesn't show up..

Here is my Select Function

public Collection Select(QueryBuilder builder) {
        List<Model> result = new List<Model>();
        List<Model> resultHistory = new List<Model>();
        Collection collection = new Collection();

        try {

            using (FileStream fs = new FileStream(GetFinalPath(builder.GetFileName()), FileMode.Open, FileAccess.Read)) {
                // check if file isn't empty
                if (fs.Length > 0) {
                    BinaryFormatter formatter = new BinaryFormatter();
                    result = (List<Model>) formatter.Deserialize(fs);

                }
            }

            // TODO: check this select
            if (builder.IsWithHistory()) {
                using (FileStream fs = new FileStream(GetFinalPath(builder.GetBackupFileName()), FileMode.Open, FileAccess.Read)) {
                    // check if file isn't empty
                    if (fs.Length > 0) {
                        BinaryFormatter formatter = new BinaryFormatter();
                        resultHistory = (List<Model>) formatter.Deserialize(fs);
                    }
                }
            }

        } catch (IOException e) {

        }

        // check if there are criterias
        if (builder.IsSelectAll()) {
            collection = new Collection(result, resultHistory);
        } else {
            var resultList = new List<Model>();
            var historyList = new List<Model>();

            // loop through initial result
            for (int i = 0; i < result.Count; i++) {
                var model = result[i];
                var properties = model.GetType().GetProperties();

                // go through each property of the model
                foreach (var property in properties) {
                    // go through each criteria of the builder map
                    foreach (var fieldItem in builder.GetMap()) {
                        // check if criteria is available in the properties
                        if (property.Name == fieldItem.Key) {
                            // check if value is equal
                            // TODO: add string operation support

                            if (property.GetValue(model).Equals(fieldItem.Value)) {
                                resultList.Add(model);
                            }
                        }
                    }
                }
            }

            // loop through history result
            for (int i = 0; i < resultHistory.Count; i++) {
                var model = result[i];
                var properties = model.GetType().GetProperties();

                // go through each property of the model
                foreach (var property in properties) {
                    // go through each criteria of the builder map
                    foreach (var fieldItem in builder.GetMap()) {
                        // check if criteria is available in the properties
                        if (property.Name == fieldItem.Key) {
                            // check if value is equal
                            // TODO: add string operation support
                            if (property.GetValue(model).Equals(fieldItem.Value)) {
                                historyList.Add(model);
                            }
                        }
                    }
                }
            }

            collection = new Collection(resultList, historyList);
        }

        return collection;
    }

Solution

  • Yes, and that's the problem.

    As far as I know the serialization process stores the length of the serialized data in the file. So if you append the data, the deserialization call can only see the first serialized data, since it reads the length of the data to be deserialized.

    // Our data to be serialized
    str1 = "ThisIsATest"; // length=11  
    str2 = "Trash";       // length=5
    
    // Thats what the serializer does: Write the length of the data, write the acutal data. The pipe is not written, just for better readability
    // Initial file write...
    11|ThisIsATest
    
    // Appending the second string
    11|ThisIsATest|5|Trash
    
    // The raw file content
    11ThisIsATest5Trash
    
    // The deserializer reads the length field and then the number of 
    // bytes as data and ends there. It does not know that there is other
    // data following, since you used to separate serialization calls...
    

    So you have two options: Follow my first answer, or, if you want to keep the file appending stuff, get the position of the stream after your formatter.Deserialize call, call the function again and again until you are at the end of the stream.