简体   繁体   中英

Why is c# creating a file before any file stream is created?

Background:
I am creating an avaloniaUI project and in it I have a json config with a class that serializes and deserializes it on initialization and editing. If the file can't be found on initialization the class makes a new one with a list of default properties. This class is supposed to be the only part of the code that can do that.

Problem:
For some reason the config file, when it does not exist already, is created before the constructor call of the config serializer class. That lead my friends and I to think that the file was being created somewhere else in the project. That can't be the case though because I've used a control f tool to comb the entire project for references of any filestreams, create commands, or a reference to the config path and I found nothing else that's capable of generating a file other than the code that's supposed to create the config but never runs. So what happens is the file is created empty before the code that's supposed to handle generation is called thus skipping the proper generation code which leads to json loading an empty string when the file is deserialized and it creates null value exceptions.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Newtonsoft.Json;

namespace RefOrganizerAvalonia.Util
{
    public class ConfigSerializer
    {
        public List<ConfigItem> Items { get; }
        
        private string _configPath;
        
        private static List<ConfigItem> BuildConfig()
        {
            return new List<ConfigItem>()
            {
                new ConfigItem("PageResultSize", 50, typeof(int))
                ,new ConfigItem("ResultsPerLine", 5, typeof(int))
            };
        }

        private List<ConfigItem> LoadConfig()
        {
            using (FileStream fs = new FileStream(_configPath, FileMode.Open))
            {
                var sr = new StreamReader(fs);
                var dataStr = sr.ReadToEnd();
                return JsonConvert.DeserializeObject(dataStr) as List<ConfigItem>;
            }
        }

        public ConfigSerializer()
        { //break point here reveals that even before any of the constructor code is executed the 
          //file is created from an unknown location
            var folder = Environment.SpecialFolder.LocalApplicationData;
            var path = Environment.GetFolderPath(folder);
            _configPath = Path.Join(path, "ref_organizer_config.json");
            Debug.WriteLine(_configPath);
            Debug.WriteLine(File.Exists(_configPath));
            if (!File.Exists(_configPath)) //never accessed because the (empty) file already 
                                           //exists by this point despite no code that can create 
                                           //it being executed
            {
                Debug.WriteLine("Config Not Found");
                //Save BuildConfig() results in json string and write to file
                Items = BuildConfig();
                SaveConfig();
            }
            else
            {
                Items = LoadConfig();
            }
        }

        private void SaveConfig()
        {
            using (FileStream fs = new FileStream(_configPath, FileMode.OpenOrCreate))
            {
                Debug.WriteLine("Save Config Triggered");
                var data = JsonConvert.SerializeObject(Items);
                Debug.WriteLine($"Serialized Config: {data}");
                var sw = new StreamWriter(fs);
                sw.Write(data);
            }
        }
    }
}

Tests Performed:

  1. Changing the call order and location of the config serializer class.

    Result: Empty file with config name and path is still created right before the initialization of config serializer.

  2. Changing the path of the _configPath variable.

    Result: Empty file created under new name.

  3. Setting SaveConfig() function to private.

    Result: No change.

Note:

If you need additional context of the avalonia project code for whatever reason send me a comment and I will post it ASAP.

In my small tests tracing your code, it appears the problem lies in the SaveConfig() method. Walking through the code should reveal that the line of code… sw.Write(data); … is executing, however, nothing is actually written to the file. Adding a Flush statement for the StreamWriter should ensure that… sw.Write(data); … gets done. Adding the Flush() command to the writer appears to actually write the data to the file.

private void SaveConfig() {
  using (FileStream fs = new FileStream(_configPath, FileMode.OpenOrCreate)) {
    Debug.WriteLine("Save Config Triggered");
    var data = JsonConvert.SerializeObject(Items);
    Debug.WriteLine($"Serialized Config: {data}");
    var sw = new StreamWriter(fs);
    sw.Write(data);
    sw.Flush();
  }
}

Edit... StreamWriter should be wrapped in a using statement.

Further tests reveal that wrapping a Using statement around the StreamWriter is needed and should be implemented. Therefore, wrapping the StreamWriter in a using statement should Flush the data for you. Below is a better approach with the using statement.

private void SaveConfig() {
  using (FileStream fs = new FileStream(_configPath, FileMode.OpenOrCreate)) {
    Debug.WriteLine("Save Config Triggered");
    var data = JsonConvert.SerializeObject(Items);
    Debug.WriteLine($"Serialized Config: {data}");
    using (var sw = new StreamWriter(fs)) {
      sw.Write(data);
    }
  }
}

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