在 JSON.NET 中序列化 DataTable 时调用读取后无法覆盖

Can't overwrite after calling read when serializing DataTable in JSON.NET

我正在使用 C# .NET CORE v5 将 class 写入 serialize/deserialize 一个 class,其中包含一个 JSON 文件的数据表 JSON.net Visual Studio 2019. 当出现以下情况时,写入操作不会覆盖,而是将DataTable追加到文件中。

  1. 读取操作发生在写入之前。
  2. 正在序列化的 Class 必须包含 DataTable。

注意:我已经剥离了所有错误处理和支持功能以减少代码的大小,然后放入控制台应用程序中。

我试过的...

  1. 我发现注释掉 DataTable 似乎可以解决问题。
  2. 如果删除行“fs.Seek(0, SeekOrigin.Begin);”在读操作中。不过不出所料,这对写操作没有影响。
  3. 在 CloseFileStream() 函数中,我添加了对 GC.Collect() 的调用以确保 GC 正在发生,但没有成功。
  4. 原始函数 WriteJSONFile() 使用了 fileStream。我将其更改为其他方法,但问题仍然存在。请参阅该功能中的评论。

当我 运行 下面的代码时,我希望 JSON 文件包含以下内容。

{
    "Name": "Test Name",
    "dt": [
        {
            "Name": "Buckaroo Banzai",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        },
        {
            "Name": "Hoban Washburne",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        },
        {
            "Name": "Dr. Morbius",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        }
    ]
}

相反,我得到了这个文件,请注意 DataTable 被复制了两次。

{
    "Name": "Test Name",
    "dt": [
        {
            "Name": "Buckaroo Banzai",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        },
        {
            "Name": "Hoban Washburne",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        },
        {
            "Name": "Dr. Morbius",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        },
        {
            "Name": "Buckaroo Banzai",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        },
        {
            "Name": "Hoban Washburne",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        },
        {
            "Name": "Dr. Morbius",
            "Num": 1,
            "Test,typeof(string)": "abcd"
        }
    ]
}
 public static class FileOperations
    { 

        private static FileStream fs = null;
        private static string currentPath = null;

        private static bool OpenFileStream(string path)
        {
            fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite, FileShare.Read);
            currentPath = path;
            return true;
        }


        public static bool ReadJSONFile<T>(string path, out T returnedInstanceOfClassFromJSONFile)
        {

            returnedInstanceOfClassFromJSONFile = default(T); //set to null

            bool bSuccessOpenFileStream = true;

            if (path != currentPath)
            {
                CloseFileStream();
                bSuccessOpenFileStream = OpenFileStream(path);
            }

            if (bSuccessOpenFileStream)
            {
                using (StreamReader reader = new StreamReader(fs, Encoding.UTF8, true, 4096, leaveOpen: true))
                using (JsonReader jreader = new JsonTextReader(reader))
                {
                    fs.Seek(0, SeekOrigin.Begin);
                    JsonSerializer serializer = new JsonSerializer();
                    returnedInstanceOfClassFromJSONFile = (T)serializer.Deserialize(jreader, typeof(T));
                }
                return true;
            }
            return false;

        }



        public static bool WriteJSONFile(string path, object objectToSerialize)
        {

            CloseFileStream();

            //I first tried using the streamwrite, but it has the same problem for example
            //using (StreamWriter sw = new StreamWriter(fs, ....)
            //using (JsonWriter writer = new JsonTextWriter(sw))
            //{
            //    serializer.Serialize(writer, objectToSerialize);
            //}
            File.WriteAllText(path, JsonConvert.SerializeObject(objectToSerialize));

            bool bSuccessOpenFileStream = OpenFileStream(path);

            return bSuccessOpenFileStream;

        }


        private static void CloseFileStream()
        {
            if (fs != null)
            {
                fs.Close();  
                fs = null;

                //shouldn't be requried, trying out of desperation
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
        }
    }

使用以下代码。请注意,如果您注释掉 ReadJSONFile,则不会出现此问题。

 static void Main(string[] args)
        {
            Simple simple = new Simple();

            string path = @"c:\somepath";
            FileOperations.WriteJSONFile(path, simple);
            FileOperations.ReadJSONFile(path, out simple); //comment this out and it works as expected
            FileOperations.WriteJSONFile(path, simple);
            FileOperations.WriteJSONFile(path, simple);
            FileOperations.WriteJSONFile(path, simple);
            FileOperations.WriteJSONFile(path, simple);
        }
    }


    public class Simple
    {
        public string Name { get; set; }
        public DataTable dt { get; set; }


        public Simple()
        {
            Name = "Test Name";

            dt = new DataTable();
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("Num", typeof(long));
            dt.Columns.Add("Test,typeof(string)");

            dt.Rows.Add("Buckaroo Banzai", 1, "abcd");
            dt.Rows.Add("Hoban Washburne", 1, "abcd");
            dt.Rows.Add("Dr. Morbius", 1, "abcd");
        }
    }


我认为这种情况发生在这条线上:

FileOperations.ReadJSONFile(path, out simple);

这一行实例化了一个简单对象

这会调用构造函数

构造函数用 3 行填充数据表

然后 ReadJSONFile 方法用文件中的数据填充对象 - 添加另外 3 行