3 changed files with 449 additions and 0 deletions
@ -0,0 +1,196 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace Apewer.Models |
||||
|
{ |
||||
|
|
||||
|
/// <summary>INI 文件。</summary>
|
||||
|
[Serializable] |
||||
|
public sealed class IniFile : IEnumerable<IniSection>, IToJson |
||||
|
{ |
||||
|
|
||||
|
List<IniSection> _sections = new List<IniSection>(); |
||||
|
|
||||
|
#region Constructors
|
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public IniFile() { } |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public IniFile(IEnumerable<IniSection> sections) |
||||
|
{ |
||||
|
if (sections == null) throw new ArgumentNullException(nameof(sections)); |
||||
|
sections.ForEach(Add); |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region CRUD
|
||||
|
|
||||
|
/// <summary>节的数量。</summary>
|
||||
|
public int Count { get => _sections.Count; } |
||||
|
|
||||
|
/// <summary>添加节。</summary>
|
||||
|
public void Add(IniSection section) |
||||
|
{ |
||||
|
if (section == null) return; |
||||
|
_sections.Add(section); |
||||
|
} |
||||
|
|
||||
|
/// <summary>添加节。</summary>
|
||||
|
public void Add(string name, TextField[] fields) => _sections.Add(new IniSection(name, fields)); |
||||
|
|
||||
|
/// <summary>获取节。</summary>
|
||||
|
public IniSection Get(string sectionName) |
||||
|
{ |
||||
|
var emptyName = sectionName.IsEmpty(); |
||||
|
foreach (var section in _sections) |
||||
|
{ |
||||
|
if (emptyName) |
||||
|
{ |
||||
|
if (section.Name.IsEmpty()) return section; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (section.Name == sectionName) return section; |
||||
|
} |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/// <summary>移除节。</summary>
|
||||
|
public void Remove(IniSection section) |
||||
|
{ |
||||
|
while (_sections.Contains(section)) _sections.Remove(section); |
||||
|
} |
||||
|
|
||||
|
/// <summary>移除节。</summary>
|
||||
|
public void Remove(string sectionName) |
||||
|
{ |
||||
|
var emptyName = sectionName.IsEmpty(); |
||||
|
foreach (var section in _sections) |
||||
|
{ |
||||
|
if (emptyName) |
||||
|
{ |
||||
|
_sections = _sections.FindAll(x => x.Name.IsEmpty()); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_sections = _sections.FindAll(x => x.Name == sectionName); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region IEnumerable<IniSection>
|
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public IEnumerator<IniSection> GetEnumerator() => new Enumerator<IniSection>(i => i < _sections.Count ? new Class<IniSection>(_sections[i]) : null); |
||||
|
|
||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region IToJson
|
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public Json ToJson() |
||||
|
{ |
||||
|
var json = Json.NewArray(); |
||||
|
_sections.ForEach(section => json.AddItem(section.ToJson())); |
||||
|
return json; |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region ToString
|
||||
|
|
||||
|
const string CRLF = "\r\n"; |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public override string ToString() => ToString(CRLF); |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public string ToString(string seperator) |
||||
|
{ |
||||
|
if (seperator.IsEmpty()) seperator = CRLF; |
||||
|
|
||||
|
var sb = new StringBuilder(); |
||||
|
|
||||
|
var noName = 0; |
||||
|
foreach (var section in _sections) |
||||
|
{ |
||||
|
if (section == null) continue; |
||||
|
|
||||
|
if (section.Name.IsEmpty()) |
||||
|
{ |
||||
|
var count = section.Count; |
||||
|
for (var i = 0; i < count; i++) |
||||
|
{ |
||||
|
var field = section.GetField(i); |
||||
|
if (Append(sb, field)) |
||||
|
{ |
||||
|
sb.Append(seperator); |
||||
|
noName += 1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
if (noName > 1) sb.Append(seperator); |
||||
|
|
||||
|
foreach (var section in _sections) |
||||
|
{ |
||||
|
if (section == null) continue; |
||||
|
|
||||
|
if (section.Name.NotEmpty()) |
||||
|
{ |
||||
|
sb.Append("["); |
||||
|
sb.Append(section.Name); |
||||
|
sb.Append("]"); |
||||
|
sb.Append(seperator); |
||||
|
|
||||
|
foreach (var field in section) |
||||
|
{ |
||||
|
if (Append(sb, field)) |
||||
|
{ |
||||
|
sb.Append(seperator); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
sb.Append(seperator); |
||||
|
} |
||||
|
|
||||
|
return sb.ToString(); |
||||
|
} |
||||
|
|
||||
|
static bool Append(StringBuilder sb, TextField field) |
||||
|
{ |
||||
|
var nameEmpty = field.Name.IsEmpty(); |
||||
|
var valueEmpty = field.Value.IsEmpty(); |
||||
|
if (nameEmpty && valueEmpty) return false; |
||||
|
|
||||
|
if (!nameEmpty) |
||||
|
{ |
||||
|
sb.Append(field.Name); |
||||
|
sb.Append(" ="); |
||||
|
} |
||||
|
|
||||
|
if (!valueEmpty) |
||||
|
{ |
||||
|
if (nameEmpty) sb.Append("; "); |
||||
|
else sb.Append(" "); |
||||
|
sb.Append(field.Value); |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,196 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
using static System.Collections.Specialized.BitVector32; |
||||
|
|
||||
|
namespace Apewer.Models |
||||
|
{ |
||||
|
|
||||
|
/// <summary>INI 节。</summary>
|
||||
|
[Serializable] |
||||
|
public sealed class IniSection : ICollection<TextField>, IEnumerable<TextField>, IToJson |
||||
|
{ |
||||
|
|
||||
|
private List<TextField> _fields = new List<TextField>(); |
||||
|
|
||||
|
/// <summary>节的名称(不含方括号)。</summary>
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public override string ToString() => $"Name = \"{Name}\", Count = {_fields.Count}"; |
||||
|
|
||||
|
#region ICollection<TextField>
|
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public int Count { get => _fields.Count; } |
||||
|
|
||||
|
/// <summary>集合是只读的。</summary>
|
||||
|
/// <value>此值始终为 FALSE。</value>
|
||||
|
public bool IsReadOnly { get => false; } |
||||
|
|
||||
|
/// <summary>添加字段。</summary>
|
||||
|
/// <exception cref="ArgumentNullException" />
|
||||
|
public void Add(TextField item) |
||||
|
{ |
||||
|
if (item == null) throw new ArgumentNullException(nameof(item)); |
||||
|
_fields.Add(item); |
||||
|
} |
||||
|
|
||||
|
/// <summary>清空字段。</summary>
|
||||
|
public void Clear() => _fields.Clear(); |
||||
|
|
||||
|
/// <summary>检查此集合是否包含指定的字段。</summary>
|
||||
|
public bool Contains(TextField item) => _fields.Contains(item); |
||||
|
|
||||
|
/// <summary>复制字段到数组中。</summary>
|
||||
|
/// <exception cref="ArgumentException" />
|
||||
|
/// <exception cref="ArgumentNullException" />
|
||||
|
/// <exception cref="ArgumentOutOfRangeException" />
|
||||
|
public void CopyTo(TextField[] array, int arrayIndex) |
||||
|
{ |
||||
|
if (array == null) throw new ArgumentNullException(nameof(array)); |
||||
|
if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex)); |
||||
|
if (array.Length - arrayIndex < _fields.Count) throw new ArgumentException("目标数组长度不足。"); |
||||
|
|
||||
|
_fields.CopyTo(array, arrayIndex); |
||||
|
} |
||||
|
|
||||
|
/// <summary>移除字段。</summary>
|
||||
|
public bool Remove(TextField item) |
||||
|
{ |
||||
|
var removed = false; |
||||
|
while (_fields.Contains(item)) |
||||
|
{ |
||||
|
_fields.Remove(item); |
||||
|
removed = true; |
||||
|
} |
||||
|
return removed; |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Enumerable
|
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public IEnumerator<TextField> GetEnumerator() => new Enumerator<TextField>(i => i < _fields.Count ? new Class<TextField>(_fields[i]) : null); |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region IToJson
|
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public Json ToJson() |
||||
|
{ |
||||
|
var fields = Json.NewObject(); |
||||
|
foreach (var field in _fields) |
||||
|
{ |
||||
|
fields.SetProperty(field.Name, field.Value); |
||||
|
} |
||||
|
|
||||
|
var json = Json.NewObject(); |
||||
|
json.SetProperty("name", Name); |
||||
|
json.SetProperty("fields", fields); |
||||
|
|
||||
|
return json; |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
/// <summary>检查此集合是否包含指定的字段。</summary>
|
||||
|
/// <param name="name">字段名称。</param>
|
||||
|
public bool Contains(string name) |
||||
|
{ |
||||
|
var count = _fields.Count; |
||||
|
for (var i = 0; i < count; i++) |
||||
|
{ |
||||
|
if (_fields[0].Name == name) return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/// <summary>获取字段。</summary>
|
||||
|
/// <exception cref="ArgumentOutOfRangeException" />"
|
||||
|
public TextField GetField(int index) |
||||
|
{ |
||||
|
if (index < 0 || index >= _fields.Count) throw new ArgumentOutOfRangeException(nameof(index)); |
||||
|
return _fields[index]; |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public string GetValue(string name) |
||||
|
{ |
||||
|
if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); |
||||
|
|
||||
|
foreach (var field in _fields) |
||||
|
{ |
||||
|
if (field.Name == name) return field.Value; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public void SetValue(string name, string value) |
||||
|
{ |
||||
|
if (name.IsEmpty()) throw new ArgumentNullException(nameof(name)); |
||||
|
|
||||
|
var count = _fields.Count; |
||||
|
var setted = false; |
||||
|
for (var i = 0; i < count; i++) |
||||
|
{ |
||||
|
if (_fields[i].Name == name) |
||||
|
{ |
||||
|
_fields[i].Value = value; |
||||
|
setted = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!setted) |
||||
|
{ |
||||
|
var field = new TextField(name, value); |
||||
|
_fields.Add(field); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>获取或设置字段。</summary>
|
||||
|
public string this[string name] { get => GetValue(name); set => SetValue(name, value); } |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public IniSection() { } |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public IniSection(string name) : this() |
||||
|
{ |
||||
|
this.Name = name; |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
/// <exception cref="ArgumentNullException" />
|
||||
|
public IniSection(string name, IEnumerable<TextField> fields) : this(name) |
||||
|
{ |
||||
|
if (fields == null) throw new ArgumentNullException(nameof(fields)); |
||||
|
_fields.AddRange(fields.Map(x => x == null ? null : new TextField(x.Name, x.Value)).FindAll(x => x != null)); |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
/// <exception cref="ArgumentNullException" />
|
||||
|
public IniSection(IEnumerable<TextField> fields) : this(null, fields) { } |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
/// <exception cref="ArgumentNullException" />
|
||||
|
public IniSection(string name, IEnumerable<KeyValuePair<string, string>> fields) : this(name) |
||||
|
{ |
||||
|
if (fields == null) throw new ArgumentNullException(nameof(fields)); |
||||
|
_fields.AddRange(fields.Map(x => new TextField(x))); |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
/// <exception cref="ArgumentNullException" />
|
||||
|
public IniSection(IEnumerable<KeyValuePair<string, string>> fields) : this(null, fields) { } |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,57 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace Apewer.Models |
||||
|
{ |
||||
|
|
||||
|
/// <summary>文本字段。</summary>
|
||||
|
[Serializable] |
||||
|
public sealed class TextField |
||||
|
{ |
||||
|
|
||||
|
/// <summary>名称。</summary>
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
/// <summary>值。</summary>
|
||||
|
public string Value { get; set; } |
||||
|
|
||||
|
/// <summary>文本字段。</summary>
|
||||
|
public TextField() { } |
||||
|
|
||||
|
/// <summary>创建文本字段。</summary>
|
||||
|
public TextField(string name, string value) |
||||
|
{ |
||||
|
this.Name = name; |
||||
|
this.Value = value; |
||||
|
} |
||||
|
|
||||
|
/// <summary>创建文本字段。</summary>
|
||||
|
public TextField(KeyValuePair<string, string> pair) |
||||
|
{ |
||||
|
this.Name = pair.Key; |
||||
|
this.Value = pair.Value; |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public override string ToString() => $"{Name} = {Value}"; |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public override bool Equals(object obj) |
||||
|
{ |
||||
|
if (obj != null && obj is TextField field) return field.Name == Name && field.Value == Value; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public override int GetHashCode() => (Name ?? "").GetHashCode() ^ (Value ?? "").GetHashCode(); |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public static implicit operator KeyValuePair<string, string>(TextField field) => field == null ? default : new KeyValuePair<string, string>(field.Name, field.Value); |
||||
|
|
||||
|
/// <summary></summary>
|
||||
|
public static implicit operator TextField(KeyValuePair<string, string> pair) => new KeyValuePair<string, string>(pair.Key, pair.Value); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
} |
Loading…
Reference in new issue