2014-02-20 91 views
2

我已經使用了這裏的類http://www.codeproject.com/Articles/1966/An-INI-file-handling-class-using-C,它運行良好,我試圖擴展它來處理段。寫入INI文件中的一段

[DllImport("kernel32")] 
private static extern long WritePrivateProfileSection(string section, 
string val, string filePath); 

public void IniWriteSection(string Section, string Value) 
{ 
    WritePrivateProfileSection(Section, Value, this.path); 
    WritePrivateProfileSection(null, null, null); 
} 

我本來有點麻煩與被寫入數據兩次,如果INI文件快速連續被編輯,所以加入

WritePrivateProfileSection(null, null, null); 

部分,而且似乎已經解決了這一問題,但是它又開始發生了,所以我猜這是行不通的。

有沒有人對我做錯了什麼建議?

+0

後的代碼中要更新的INI文件。 – Aybe

+0

1966年聽起來很正確;)似乎可能有這方面的已知問題。看到這個討論:http://www.codeproject.com/Questions/200917/WritePrivateProfileSection-does-not-over-write。你應該開始考慮使用除ini文件之外的其他東西。 –

+0

我還不能,因爲我問了這個問題還沒有8個小時。 – Beresford

回答

2

問題是,你寫入ini文件是無效的。你寫的值必須是key1=value1\0key2=value2\0的形式。根據您以前對原始代碼的修訂,您不會以任何形式編寫任何內容,只是一些文本。

ini文件解析器將在節開始之後處理任何內容作爲節的一部分。但它只將key=value行視爲有效的鍵/值對。它只會替換最後一個有效的鍵/值對。除此以外的任何東西都將保持原樣。

至少......這就是我所觀察到的......我不知道這是否是Windows實現的實際規範。


您必須使用正確的格式編寫。你寫的每個值都必須與一個鍵配對。應該將多個值寫爲由空字符分隔的單獨的鍵。如果您有多行寫入,則必須將它們寫入單獨的(唯一)密鑰。

你應該使用更多的東西是這樣的:

public class IniFile 
{ 
    private readonly string path; 
    public IniFile(string path) 
    { 
     if (path == null) 
      throw new ArgumentNullException("path"); 
     this.path = path; 
    } 
    public string Path { get { return path; } } 

    public bool WriteSection(string section, string key, IEnumerable<string> lines) 
    { 
     if (String.IsNullOrWhiteSpace(section)) 
      return false; 
     if (String.IsNullOrWhiteSpace(key)) 
      return false; 
     return WritePrivateProfileSection(section, ToSectionValueString(key, lines)); 
    } 

    private string ToSectionValueString(String key, IEnumerable<string> lines) 
    { 
     if (lines == null) 
      return null; 
     if (lines.Count() == 1) 
      return key + "=" + lines.Single(); 
     return String.Join("\0", 
      lines.Select((line, i) => (key + "." + i) + "=" + line) 
     ); 
    } 

    public bool WriteSection(string section, IEnumerable<KeyValuePair<string, string>> values) 
    { 
     if (String.IsNullOrWhiteSpace(section)) 
      return false; 
     return WritePrivateProfileSection(section, ToSectionValueString(values)); 
    } 

    private string ToSectionValueString(IEnumerable<KeyValuePair<string, string>> values) 
    { 
     if (values == null) 
      return null; 
     return String.Join("\0", values.Select(kvp => kvp.Key + "=" + kvp.Value)); 
    } 

    public List<KeyValuePair<string, string>> ReadSection(string section) 
    { 
     var buff = new byte[SectionSizeMax]; 
     var count = GetPrivateProfileSection(section, buff); 
     return ToSectionValueList(buff, (int)count); 
    } 

    private List<KeyValuePair<string, string>> ToSectionValueList(byte[] buff, int count) 
    { 
     return EnumerateValues(buff, count) 
      .Select(v => v.Split('=')) 
      .Where(s => s.Length == 2) 
      .Select(s => new KeyValuePair<string, string>(s[0], s[1])) 
      .ToList(); 
    } 

    private IEnumerable<string> EnumerateValues(byte[] buff, int count) 
    { 
     var value = new StringBuilder(); 
     foreach (var b in buff) 
     { 
      var c = (char)b; 
      if (c != '\0') 
      { 
       value.Append(c); 
      } 
      else 
      { 
       yield return value.ToString(); 
       value.Clear(); 
      } 
     } 
    } 

    [DllImport("kernel32")] 
    private static extern bool WritePrivateProfileSection(string lpAppName, string lpString, string lpFileName); 
    private bool WritePrivateProfileSection(string lpAppName, string lpString) 
    { 
     return WritePrivateProfileSection(lpAppName, lpString, path); 
    } 

    [DllImport("kernel32")] 
    private static extern uint GetPrivateProfileSection(string lpAppName, byte[] lpReturnedString, uint nSize, string lpFileName); 
    private uint GetPrivateProfileSection(string lpAppName, byte[] lpReturnedString) 
    { 
     return GetPrivateProfileSection(lpAppName, lpReturnedString, (uint)lpReturnedString.Length, path); 
    } 
    const uint SectionSizeMax = 0x7FFF; 
} 

然後寫這樣的:

var lines = new List<string>(); 
lines.Add("..."); 
lines.Add("..."); 
// ... 

ini.WriteSection("autoexec", "line", lines); 
+0

_它只會替換最後一個有效的鍵/值對。除此之外的任何東西都將保持原樣。這解釋了這種行爲。 autoexec部分只是一個沒有任何鍵值對的字符串,就像普通的autoexec.bat文件一樣。如果我寫入有效數據,那麼iniWriteSection按預期工作。謝謝。 – Beresford

1

我找到了一個解決辦法,你需要用

ini.IniWriteValue("autoexec", null, null); 

刪除你正在寫的部分,然後寫你的部分

ini.IniWriteSection("autoexec", strAutoexecSection); 

,則不需要此行。

WritePrivateProfileSection(null, null, null);