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;
}
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.