读取外部配置文件

22

我有一个使用C# .Net编写的控制台应用程序,用于执行FTP操作。

目前,我在自定义配置节中指定设置,例如:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="ftpConfiguration" type="FileTransferHelper.FtpLibrary.FtpConfigurationSection, FileTransferHelper.FtpLibrary" />
  </configSections>

  <ftpConfiguration>
      <Environment name="QA">
        <sourceServer hostname="QA_hostname"
                      username="QA_username"
                      password="QA_password"
                      port="21"
                      remoteDirectory ="QA_remoteDirectory" />
        <targetServer downloadDirectory ="QA_downloadDirectory" />

      </Environment>
  </ftpConfiguration>

</configuration>

我想在命令行中指定一个外部配置文件。

但是!!!

我刚刚意识到上面的“FtpConfiguration”部分并不真正属于应用程序的app.config文件。我的最终目标是,我将有许多定时任务执行我的控制台应用程序,就像这样:

FileTransferHelper.exe -c FtpApplication1.config
FileTransferHelper.exe -c FtpApplication2.config
...
FileTransferHelper.exe -c FtpApplication99.config
因此,我相信我走了一条错误的路线,我真正想要的是在我的自定义xml文档中读取内容,但继续使用System.Configuration来获取值……而不是读取XmlDocument并序列化以获取节点/元素/属性。(虽然,如果有人能向我展示一些简单的代码,我也不反对后一种方法)指针将不胜感激。谢谢。
更新: 我接受的答案是链接到另一个StackOverflow问题,下面是我的代码 - 正是我正在寻找的 - 使用OpenMappedExeConfiguration打开我的外部配置文件。
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = @"D:\Development\FileTransferHelper\Configuration\SampleInterface.config";

Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);

FtpConfigurationSection ftpConfig = (FtpConfigurationSection)config.GetSection("ftpConfiguration");

1
只是提醒一下,如果你决定只解析XML:XmlDocument是在C#中处理XML的旧方法,虽然你当然可以使用它,但我建议使用Linq-to-Xml的一部分XDocument。 - Magus
3个回答

23

如果您想使用 System.Configuration 打开自定义文件,您可能希望检查这篇文章:Loading custom configuration files。Oliver 用非常直接的方式解释了这个问题。

由于您想要读取通过命令行传递给应用程序的参数,您可能需要查看这篇 MSDN 文章:Command Line Parameters Tutorial

如果您更喜欢使用自定义方法,则有几种方法可以实现这一点。其中一种可能性是实现一个加载器类,并消耗您的自定义配置文件。

例如,假设有一个简单的配置文件如下:

spec1.config

<?xml version="1.0" encoding="utf-8"?>
<Settings>
    <add key="hostname" value="QA_hostname" />
    <add key="username" value="QA_username" />
</Settings>
一个非常简单的哈希表结构(键-值对)。一个实现的解析器/读取器将看起来像这样:
        private Hashtable getSettings(string path)
        {
            Hashtable _ret = new Hashtable();
            if (File.Exists(path))
            {
                StreamReader reader = new StreamReader
                (
                    new FileStream(
                        path,
                        FileMode.Open,
                        FileAccess.Read,
                        FileShare.Read)
                );
                XmlDocument doc = new XmlDocument();
                string xmlIn = reader.ReadToEnd();
                reader.Close();
                doc.LoadXml(xmlIn);
                foreach (XmlNode child in doc.ChildNodes)
                    if (child.Name.Equals("Settings"))
                        foreach (XmlNode node in child.ChildNodes)
                            if (node.Name.Equals("add"))
                                _ret.Add
                                (
                                    node.Attributes["key"].Value,
                                    node.Attributes["value"].Value
                                );
            }
            return (_ret);
        }

同时,您仍然可以使用ConfigurationManager.AppSettings[]从原始的app.config文件中读取。


15
如果您选择自定义路径,我会建议您使用JSON来存储配置,然后反序列化以加载它并序列化以写入它。Json.NET允许您轻松实现此操作。
您的XML如下:
<ftpConfiguration>
  <Environment name="QA">
    <sourceServer hostname="QA_hostname"
                  username="QA_username"
                  password="QA_password"
                  port="21"
                  remoteDirectory ="QA_remoteDirectory" />
    <targetServer downloadDirectory ="QA_downloadDirectory" />

  </Environment>
</ftpConfiguration>

在JSON中会像这样:

{
  "FtpConfiguration": {
    "Environment": {
      "Name": "QA",
      "SourceServer": {
        "HostName": "QA_hostname",
        "UserName": "QA_username",
        "Password": "QA_password",
        "Port": "21",
        "RemoteDirectory": "QA_remoteDirectory"
      },
      "TargetServer": {
        "DownloadDirectory": "QA_downloadDirectory"
      }
    }
  }
}

你的类会像这样:
class Config
{
    public FtpConfiguration FtpConfiguration { get; set; }
}

class FtpConfiguration
{
    public Environment Environment { get; set; }
}

class Environment
{
    public SourceServer SourceServer { get; set; }
    public TargetServer TargetServer { get; set; }
}

class SourceServer
{
    public string HostName { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
    public int Port { get; set; }
    public string RemoteDirectory { get; set; }
}

class TargetServer
{
    public string DownloadDirectory { get; set; }
}

您可以将设置保存到对象中,如下所示:

var config = new Config()
{
    FtpConfiguration = new FtpConfiguration()
    {
        Environment = new Environment()
        {
            SourceServer = new SourceServer()
            {
                HostName = "localhost",
                UserName = "jaxrtech",
                Password = "stackoverflowiscool",
                Port = 9090,
                RemoteDirectory = "/data",
            },
            TargetServer = new TargetServer()
            {
                DownloadDirectory = "/downloads"
            }
        }
    }
};

你可以像这样写入文件(如果是较大的文件,则可以使用Stream):

然后,您可以像这样编写文件:

string json = JsonConvert.SerializeObject(config);
File.WriteAllText("config.json", json);

你可以像这样读取文件(同样可以使用 Stream):

然后你可以像这样在文件中阅读

string json = File.ReadAllText("config.json");
Config config = JsonConvert.DeserializeObject<Config>(json);

9

我偏爱使用XDocument来解决问题。我没有测试过它,所以可能会有一些细微的问题,但这是为了证明我的观点。

public Dictionary<string, string> GetSettings(string path)
{

  var document = XDocument.Load(path);

  var root = document.Root;
  var results =
    root
      .Elements()
      .ToDictionary(element => element.Name.ToString(), element => element.Value);

  return results;

}

将返回一个包含来自形式为xml的元素名称和值的字典:
<?xml version="1.0" encoding="utf-8"?>
<root>
  <hostname>QA_hostname</hostname>
  <username>QA_username</username>
</root>

我觉得这个解决方案很好,因为它总体上很简洁。

再说一遍,我不认为这会完全按照原样工作。使用XAttributes和XElements等,你肯定可以使其更像你的原始方案。过滤起来也很容易。


@OnoSendai:这真的是我最喜欢的Linq部分之一,我认为很多人甚至没有意识到它的存在。虽然它相对较新,但命名空间的工作方式可能有点令人困惑。 - Magus
这是我最喜欢的解决方案,清晰明了,并且对CPU的占用不太高。我不知道这是否比其他方案更快,将来我会试一下。 - luka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接