如何在 C++/CLI 或 C# 中将静态结构数据保存到二进制文件

Posted

技术标签:

【中文标题】如何在 C++/CLI 或 C# 中将静态结构数据保存到二进制文件【英文标题】:How to save static struct data to binary file in c++/CLI or C# 【发布时间】:2016-03-14 09:42:34 【问题描述】:

我想在关闭程序时保存数据并在打开程序时加载数据。 我的结构是这样的

public ref class FormConfig

    // Connect form
public: 
    static Int32    Connect_SlaveNo = 0; // + 1 // Axes number                      
    static Int32    Connect_BaudrateNo = 0; 
    static Int32    Connect_PortNo= 0; // port number
    static bool     Connect_DemoCheck = false;  
    static String^  Connect_ConnectInfo = String::Empty;    

;

我尝试将我的 static 结构数据读/写到二进制文件,但没有成功。 我认为要读/写,需要将静态结构转换为字节数组。我也使用了序列化,但它不能与静态结构一起使用。

我也尝试过单例而不是静态结构,但我遇到了与这个问题How to do singleton serialization in C#? 相同的问题。

使用非托管C++,一切都像这样非常简单,但不能在.Net中使用。

struct Medicazos m = "Bob", "Password", "Feet", 123, 456;

FILE* f = fopen(...);
fwrite(&m, sizeof(struct Medicazos), 1, f);

谁能帮帮我?

【问题讨论】:

看this 感谢您的建议。我知道序列化静态结构时没有任何意义。但我不知道如何将结构的静态数据保存到二进制文件:/ 【参考方案1】:

嗯...一种方法是不要在结构中使用static 字段。为什么不创建一个包含单个结构实例的静态字段呢?还是一开始就避免使用静态?

无论如何,您始终可以编写自己的序列化方法。就这么简单(在 C# 中,因为那是我更流利的,你也注意到了 C#):

public class MyClass

  public static int Field1;
  public static int Field2;

  public static byte[] SerializeStatics()
  
    using (var ms = new MemoryStream())
    
      using (var bw = new BinaryWriter(ms))
      
        bw.Write(Field1);
        bw.Write(Field2);
      

      return ms.ToArray();
    
  

反序列化是相同的——在这个例子中只使用BinaryReaderReadInt32

此外,一些序列化程序确实支持静态属性,您通常只需将它们标记为显式序列化即可。默认值非常有意义 - 您正在序列化一个实例,包含静态类数据有什么意义?

对于风格说明:同样,这可能只是意味着您使用 static 的方式与您在其他环境或语言中习惯的方式相同,但在 C++/CLI 或 C# 中有更好的方法。 statics 倾向于在 .NET 中避免使用(实际上,许多现代编程方法),主要的例外是缓存的各种示例。 statics 的主要缺点是它有效地扩展了应用程序中每一行代码的状态(以及任何其他可以引用您的应用程序的人),这反过来又是常见的错误来源。您通常希望保持状态尽可能小,而是依赖参数和返回值 - 例如,当您开始使用多线程和托管环境时,这尤其有用。

【讨论】:

非常感谢您的评论。我序列化了静态结构,因为我想将该数据保存到二进制文件中。手动序列化方法可能不适合具有多种类型字段的 struct。由于二进制读取器需要知道结构中字段的类型,因此反序列化会出现问题。您关于静态的注释非常有用。但是我想知道如何在没有静态类和单例的情况下在 .Net 中使用诸如全局变量之类的东西? 他/她的建议之一是创建一个结构类型的全局变量,然后包含实例(非静态)字段。然后你应该能够序列化该结构。 @chinhngo 为什么没有单例?这是做你想做的事情的方法之一,它允许你很好地使用序列化。为什么要将它作为“全局变量”呢?通常,全局变量会使您的程序更难推理。拥有全局变量(而不是变量)可能很好,但这似乎不是你的情况。您总是有一些合理的上下文可以拥有这些值,那么为什么不使用它呢?或者也许使用依赖注入之类的东西来处理数据应该可用的地方。 谢谢@Luaan,我用的是singleton,问题解决了。【参考方案2】:

两天后,我找到了解决问题的方法,希望对您有所帮助。

使用Singleton 代替static struct。 我的代码是用 C++/CLI 编写的

保存到二进制文件

#include "stdafx.h"
using namespace System;
using namespace System::IO;
using namespace System::Collections;
using namespace System::Runtime::Serialization::Formatters::Binary;
using namespace System::Runtime::Serialization;



[Serializable]
public ref class Singleton
   
public:
    String^ str1;
    String^ str2;
    Int32 num;
public:
    // Private constructor allowing this type to construct the singleton.
    Singleton()
    
        // Do whatever is necessary to initialize the singleton.
        str1 = "2222";
        num =12345;
    
public:static Singleton^ theInstance ;


public: static property Singleton^ Instance
         Singleton^ get()
            
                if (theInstance == nullptr)
                    theInstance = gcnew Singleton();
                return theInstance;
            
        
;


int main()
   
     FileStream^ fs = gcnew FileStream( "C:\\DataFile.dat",FileMode::OpenOrCreate );
    Singleton^ a =  Singleton::Instance;
    Console::WriteLine( "Reason: 0",a->str1);
    BinaryFormatter^ formatter = gcnew BinaryFormatter; 
    formatter->Serialize(fs, a);
    fs->Close(); 


    return 0;

要从二进制文件中读取,只需更改 Main()

int main()
   
         Singleton^ a =  Singleton::Instance;   
    FileStream^ fs1 = gcnew FileStream( "C:\\DataFile.dat",FileMode::Open );    //
    System::IO::FileInfo ^_FileInfo = gcnew System::IO::FileInfo("C:\\DataFile.dat");   
    fs1->Position =0;
    BinaryFormatter^ formatter1 = gcnew BinaryFormatter;
    Singleton^ b = safe_cast<Singleton^>(formatter1->Deserialize(fs1));
    fs1->Close();
    Console::WriteLine( "result: 0", b->str1 ); 

    return 0;



【讨论】:

以上是关于如何在 C++/CLI 或 C# 中将静态结构数据保存到二进制文件的主要内容,如果未能解决你的问题,请参考以下文章

将 C# 对象(包含静态对象成员)作为参数传递给 C++/CLI 程序

如何在不同线程的 C++/CLI 中将图像数据从 BitmapSource (WPF) 复制到 cv::Mat (OpenCV)?

在 C# 中将结构类型存储在列表或字典中

如何在 C# 中将列表或数组转换为子类型?

如何使用 c++/cli 从 C# 流到 OpenCV Mat?

在 c++/cli 中将 printf 数据写入字符串变量