在将由C#读取的.txt文件中包含控制字符

本文关键字:文件 包含 控制字符 txt 读取 | 更新日期: 2023-09-27 17:59:19

我正在处理一个项目,该项目使用一个普通的ASCI.txt文件作为键/值配置文件。ConfigFile.txt的当前格式类似于

FirstName=Elmer | LastName=Fudd | UserId=EFudd |密码=fubar |日期=2016年7月29日

这很容易读入程序,并使用KeyValuePairs创建字典,代码类似于:

   using (FileStream fs = new FileStream("ConfigFile.txt", FileMode.Open))
    {
      using (StreamReader sr = new StreamReader(fs))
      {
        string fileText = sr.ReadToEnd();
        //  Tokenize the entire file string into separate key=value strings.
        string[] tokens = fileText.Split('|');
        //  Iterate through all of the key=value strings, tokenize each one into a key=Value 
        //  pair and add the key and value as separate strings into the dictionary.
        foreach (string token in tokens)
        {
          string[] keyValuePair = token.Split('=');
          configDict.Add(keyValuePair[0], keyValuePair[1]);
        }
      }
    }

它首先使用"|"作为分隔符将每个键/值拆分为一个单独的字符串。

FirstName=Elmer

LastName=Fudd

UserId=EFudd

密码=foobar

日期=2016年7月29日

然后,对于每个键/值字符串,它在"="分隔符上分离键和值,创建KeyValuePair,并将其插入字典中,以便稍后在程序中查找。

到目前为止还不错。指示用户不要使用任何分隔符创建密码。然而,在将密码包含在文件中之前,我现在必须对其进行加密,并且加密例程可以生成从0x20到0x7F的任何可打印字符。因此,一个加密的密码最终可能包含其中一个或两个分隔符。我最终可能会发现"foobar"(或其他任何东西)被加密引擎加密为P#|=g%。这会打乱拆分函数正常工作的能力。

因此,我想更改在Notepad.txt文件中键入的分隔符以控制字符,这样我就可以使用0x1E(记录分隔符)而不是"|"分隔符,并将"="符号替换为0x1F(单位分隔符)。

我可以直接用C#进行转义和编码,没有任何问题,但我如何修改原始的.txt磁盘文件,使其能够正确地以单个(不可打印)字符的形式读取分隔符?

在将由C#读取的.txt文件中包含控制字符

因此,与其使用这样的纯文本,不如使用适当的序列化格式,例如JSON。

有一些工具可以为你做艰苦的工作
内置的System.Web.Script.Serialization命名空间有一些工具可以使用,但我更喜欢使用Json.Net。如果你有Visual Studio,你可以用nuGet安装它(如果你需要更多帮助,请在评论中告诉我)。

但一旦你把它添加到你的项目中,你就可以做一些类似于的事情

using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
namespace ConsoleApplication1
{
    public class Program
    {
        static void Main(string[] args)
        {
            var dict = new Dictionary<string, string>();
            dict.Add("FirstName", "Elmer");
            dict.Add("LastName", "Fudd");
            dict.Add("Password", @"'a'ansld'sb'b8d95nj");
            var json = JsonConvert.SerializeObject(dict);
            File.WriteAllText("ConfigFile.txt, json);
            var txt = File.ReadAllText("ConfigFile.txt");
            var newDict = JsonConvert.DeserializeObject<Dictionary<string, string>>(txt);
        }
    }
}

和ConfigFile.txt看起来像这个

{"FirstName":"Elmer","LastName":"Fudd","Password":"''a''ansld''sb''b8d95nj"}

如果你想让它更易于阅读,可以使用

var json = JsonConvert.SerializeObject(dict, Formatting.Indented);

你会得到

{
  "FirstName": "Elmer",
  "LastName": "Fudd",
  "Password": "''a''ansld''sb''b8d95nj"
}

您可以将整数转换为字符,所以只需执行以下操作。。。

string[] tokens = fileText.Split((char)0x1e);
// ...
string[] keyValuePair = token.Split((char)0x1f);

但将密码编码为base64会更容易、更干净。。。

string base64 = Convert.ToBase64String(passwordHash);
byte[] passwordHash = Convert.FromBase64String(base64);

注意:散列/加密数据可能会包含这些字符,所以我不会只是将散列转储到文本文件中。

以下类使用正则表达式提取字符串段,并支持不可打印字符的密码:0x00。。0xFF该类包括配置段的属性

您可以在.NEt Fiddle 上运行演示示例

using System;
using System.Text.RegularExpressions;

class ConfigParser
{
    public string Text { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string UserId { get; set; }
    public string Password { get; set; }
    public string Date { get; set; }
    public ConfigParser(string text)
    {
        Text =text;
        Parse(text);
    }

    private static string pattern = @"
     ^FirstName=(?<firstname>'w+)    '|          
     LastName=(?<lastname>'w+)       '|              
     UserId=(?<userid>'w+)           '|                  
     Password=(?<pasword>.+)        
     Date=(?<date>.+)                         
     $
    ";
    private Regex regex = new Regex(pattern,
           RegexOptions.Singleline
           | RegexOptions.ExplicitCapture
           | RegexOptions.CultureInvariant
           | RegexOptions.IgnorePatternWhitespace
           | RegexOptions.Compiled
           );

    private void Parse(string text)
    {
        Console.WriteLine("text: {0}",text);
        Match m = regex.Match(text);
        FirstName = m.Groups["firstname"].ToString();
        LastName = m.Groups["lastname"].ToString();
        UserId = m.Groups["userid"].ToString();
        Password = m.Groups["pasword"].ToString();
        Date = m.Groups["date"].ToString();
    }
}

如何使用:

   var text ="your text here"; 
   var c = new ConfigParser(text );             
   you can access the properties of the class: FirstName, LastName,....
   Console.WriteLine("firstname: {0}", c.FirstName);
   Console.WriteLine("lastname: {0}", c.LastName);
   Console.WriteLine("UserId: {0}", c.UserId);
   Console.WriteLine("Password: {0}", c.Password);
   Console.WriteLine("date {0}", c.Date);

样本输出:密码包括不可打印的字符|分隔符和符号

text: FirstName=Elmer|LastName=Fudd|UserId=EFudd|Password=fg%|uy|◄¶|hj↑khg|Date=7/29/2016
firstname: Elmer
lastname: Fudd
UserId: EFudd
Password: fg%|uy|◄¶|hj↑khg
date: 7/29/2016

最简单的答案:

使用ALT数字键盘数值技巧将特殊字符插入字符串。记录组ALT-31(▼)定义键/值对和项目组ALT-30的末尾(▲)以从值中分隔键。将字符串另存为UTF-8。

分隔符的代码是

private static char tokenDelimiter = ('▲');
private static char keyValuePairDelimiter = ('▼');

使用相同的ALT数字键盘技巧输入上下三角形。包括禁止编辑或删除黑色三角形的说明,并解释其含义。

它让我回到了以前的DOS时代。实现起来很简单,只需5分钟,而且不需要对现有的代码库进行实质性更改,只需更改两个分隔符即可。