如何将变量保存到新的文本文件中,以便下次程序运行时加载这些变量?

Posted

技术标签:

【中文标题】如何将变量保存到新的文本文件中,以便下次程序运行时加载这些变量?【英文标题】:How Do I save variables to a new text file so that those variables are loaded the next time the program runs? 【发布时间】:2013-03-07 18:22:19 【问题描述】:

这里有新的 C#er。我正在制作基于控制台的 RPG。它进展顺利,但我需要找出如何保存游戏。我猜想有一种方法可以将我的应用程序中的变量保存到一个文本文件中,该文件可用于在应用程序再次运行时加载变量。不幸的是,我不知道从哪里开始。

我还需要一种方法在加载保存文件时转到代码中的某个点。

我的一些变量包括:

int xCoordinate, yCoordinate, hp, hpmax, level;

任何示例代码将不胜感激。

【问题讨论】:

请告诉我们您尝试了什么? 我还没有真正尝试过任何东西。我对它进行了一些研究,但我发现它似乎不适合我正在尝试做的事情。 这是 Visual Studio 中的项目吗?如果是的话,我可以展示一个巧妙的技巧。 是的,Visual C# express。我也有 Visual Studio 2012,但我在 C# express 中启动了这个项目,所以这就是我正在使用的。 在新版本的 Visual Studio 中,不要忘记将 System.IO 添加到 StreamReader 和 StreamWriter。 【参考方案1】:

将一些变量写入文本文件很简单:

TextWriter tw = new StreamWriter("SavedGame.txt");

// write lines of text to the file
tw.WriteLine(xCoordinate);
tw.WriteLine(yCoordinate);

// close the stream     
tw.Close();

然后将它们读回:

// create reader & open file
TextReader tr = new StreamReader("SavedGame.txt");

// read lines of text
string xCoordString = tr.ReadLine();
string yCoordString = tr.ReadLine();

//Convert the strings to int
xCoordinate = Convert.ToInt32(xCoordString);
yCoordinate = Convert.ToInt32(yCoordString);

// close the stream
tr.Close();

【讨论】:

感谢您的帮助。我想我会用这个,但你忘了你的;s。【参考方案2】:

您可以使用二进制序列化来相当轻松地完成此任务。首先,创建一个包含您要编写的所有变量的类:

[Serializable]
class Data

    int x;
    int y;

然后按如下方式使用:

Data data = new Data();

//Set variables inside data here...

// Save data
BinaryFormatter formatter = new BinaryFormatter();
using (FileStream stream = File.OpenWrite("C:\\Temp\\bin.bin"))

    formatter.Serialize(stream, data);

【讨论】:

【参考方案3】:

您可以将变量保存到 XML 文件中,并在下次启动时加载它们,该过程称为 serialization。 See here 用于一个帮助类,它可以序列化和反序列化大多数任何 c# 对象(包括列表,但不包括字典)到 XML 文件和从 XML 文件中反序列化。

如果您只想将几个值传输到下一个控制台应用程序,您可以使用command line parameters 或pipe。

【讨论】:

这似乎是一个不错的选择,但如果我愿意,这是否允许我从头开始加载应用程序?【参考方案4】:

我的变量保存脚本(隐藏、加密、可编辑、更改、保存、删除)

public class SavingPlugin


    public static void SaveVariable(string savename, TypeCode tc, object value,string Encryption_password)
    
        string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + savename + "." + tc.ToString();

        if (!File.Exists(path))
        
            var myfile = File.Create(path);
            myfile.Close();
            string val = value.ToString();
            string encrypted = StringCipher.Encrypt(val, Encryption_password);
            File.WriteAllText(path, encrypted);
            File.SetAttributes(path, FileAttributes.Hidden);

        
        else
        
            string txt = "";
            try
            
                txt = StringCipher.Decrypt(File.ReadAllText(path), Encryption_password);
                File.SetAttributes(path, FileAttributes.Normal);
                string val = value.ToString();
                string encrypted = StringCipher.Encrypt(val, Encryption_password);
                File.WriteAllText(path, encrypted);
                File.WriteAllText(path, encrypted);
                File.SetAttributes(path, FileAttributes.Hidden);
            
            catch
            
                MessageBox.Show("Incorrect password : " + Encryption_password + " for the variable : " + savename + "." + tc.ToString());
            

        
    

    public static object GetVariable(string savename, TypeCode tc, string Encryption_password)
    
        string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + savename + "." + tc.ToString();
        File.SetAttributes(path, FileAttributes.Normal);
        string txt = "";

        try
        
            txt = StringCipher.Decrypt(File.ReadAllText(path), Encryption_password);
            File.SetAttributes(path, FileAttributes.Hidden);
            var value = Convert.ChangeType(txt, tc);
            return value;
        
        catch
        
            MessageBox.Show("Incorrect password : " + Encryption_password + " for the variable : " + savename + "." + tc.ToString());
            return null;
        


    

    public static void DeleteVariable(string savename,TypeCode tc)
    
        string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + savename + "." + tc.ToString();
        File.SetAttributes(path,FileAttributes.Normal);
        File.Delete(path);
    

    public static bool Exists(string savename,TypeCode tc)
    
        string path = AppDomain.CurrentDomain.BaseDirectory + @"\" + savename + "." + tc.ToString();
        bool _true = true;

        try
        
            File.SetAttributes(path, FileAttributes.Normal);
            File.SetAttributes(path, FileAttributes.Hidden);
        
        catch
        
            _true = false;
        

        return _true;
    


public static class StringCipher

    // This constant is used to determine the keysize of the encryption algorithm in bits.
    // We divide this by 8 within the code below to get the equivalent number of bytes.
    private const int Keysize = 256;

    // This constant determines the number of iterations for the password bytes generation function.
    private const int DerivationIterations = 1000;

    public static string Encrypt(string plainText, string passPhrase)
    
        // Salt and IV is randomly generated each time, but is preprended to encrypted cipher text
        // so that the same Salt and IV values can be used when decrypting.  
        var saltStringBytes = Generate256BitsOfRandomEntropy();
        var ivStringBytes = Generate256BitsOfRandomEntropy();
        var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
        
            var keyBytes = password.GetBytes(Keysize / 8);
            using (var symmetricKey = new RijndaelManaged())
            
                symmetricKey.BlockSize = 256;
                symmetricKey.Mode = CipherMode.CBC;
                symmetricKey.Padding = PaddingMode.PKCS7;
                using (var encryptor = symmetricKey.CreateEncryptor(keyBytes, ivStringBytes))
                
                    using (var memoryStream = new MemoryStream())
                    
                        using (var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                        
                            cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
                            cryptoStream.FlushFinalBlock();
                            // Create the final bytes as a concatenation of the random salt bytes, the random iv bytes and the cipher bytes.
                            var cipherTextBytes = saltStringBytes;
                            cipherTextBytes = cipherTextBytes.Concat(ivStringBytes).ToArray();
                            cipherTextBytes = cipherTextBytes.Concat(memoryStream.ToArray()).ToArray();
                            memoryStream.Close();
                            cryptoStream.Close();
                            return Convert.ToBase64String(cipherTextBytes);
                        
                    
                
            
        
    

    public static string Decrypt(string cipherText, string passPhrase)
    
        // Get the complete stream of bytes that represent:
        // [32 bytes of Salt] + [32 bytes of IV] + [n bytes of CipherText]
        var cipherTextBytesWithSaltAndIv = Convert.FromBase64String(cipherText);
        // Get the saltbytes by extracting the first 32 bytes from the supplied cipherText bytes.
        var saltStringBytes = cipherTextBytesWithSaltAndIv.Take(Keysize / 8).ToArray();
        // Get the IV bytes by extracting the next 32 bytes from the supplied cipherText bytes.
        var ivStringBytes = cipherTextBytesWithSaltAndIv.Skip(Keysize / 8).Take(Keysize / 8).ToArray();
        // Get the actual cipher text bytes by removing the first 64 bytes from the cipherText string.
        var cipherTextBytes = cipherTextBytesWithSaltAndIv.Skip((Keysize / 8) * 2).Take(cipherTextBytesWithSaltAndIv.Length - ((Keysize / 8) * 2)).ToArray();

        using (var password = new Rfc2898DeriveBytes(passPhrase, saltStringBytes, DerivationIterations))
        
            var keyBytes = password.GetBytes(Keysize / 8);
            using (var symmetricKey = new RijndaelManaged())
            
                symmetricKey.BlockSize = 256;
                symmetricKey.Mode = CipherMode.CBC;
                symmetricKey.Padding = PaddingMode.PKCS7;
                using (var decryptor = symmetricKey.CreateDecryptor(keyBytes, ivStringBytes))
                
                    using (var memoryStream = new MemoryStream(cipherTextBytes))
                    
                        using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                        
                            var plainTextBytes = new byte[cipherTextBytes.Length];
                            var decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
                            memoryStream.Close();
                            cryptoStream.Close();
                            return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount);
                        
                    
                
            
        
    

    private static byte[] Generate256BitsOfRandomEntropy()
    
        var randomBytes = new byte[32]; // 32 Bytes will give us 256 bits.
        using (var rngCsp = new RNGCryptoServiceProvider())
        
            // Fill the array with cryptographically secure random bytes.
            rngCsp.GetBytes(randomBytes);
        
        return randomBytes;
    

如何使用:

SavingPlugin.SaveVariable("int16",TypeCode.Int16,15,"awwdad");
MessageBox.Show(SavingPlugin.GetVariable("int16", TypeCode.Int16,"awwdad").ToString());

您可以使用 SaveVariable 更改已经存在的变量的值,但您需要输入正确的密码

【讨论】:

以上是关于如何将变量保存到新的文本文件中,以便下次程序运行时加载这些变量?的主要内容,如果未能解决你的问题,请参考以下文章

C# webform中如何做到允许用户自由拖动控件-比如文本框到新的位置,并保存,下次用户使用的时候还可以恢复

如何突出显示文本,然后将其保存以便下次访问同一页面时显示?

将 Interactive JTable 的内容保存到 .txt 文件以在下次运行时读取它

Tkinter:如何将文本小部件中输入的文本保存到新窗口中?

将数据保存到外部文件

制作一个按钮,在程序下次运行时保存列表