kernel32.dll - GetPrivateProfileSectionNamesA

时间:2009-07-22 11:18:10

标签: c# unicode ini

我在阅读使用不同编码的IniFiles时遇到问题。如果我读取一个Unicode文件,GetPrivateProfileSectionNamesA似乎偶然发现了第一行。 ASCII或ANSI工作正常。 我写了一个小程序来说明我的问题。首先是输出,然后是程序。 我真的不关心UTF7和UTF32,但我没有得到的是UTF8部分。我是否必须使用其他功能来读取Unicode IniFiles?我做错了吗? 希望有人可以帮助我, 谢谢 诺贝特

我得到了什么:

IniEntriesWithSectionInFirstLine
first section using System.Text.ASCIIEncoding is FirstSectionInFirstLine
first section using System.Text.Latin1Encoding is FirstSectionInFirstLine
first section using System.Text.UTF7Encoding is
first section using System.Text.UTF8Encoding is SecondSection
first section using System.Text.UTF32Encoding is SecondSectio????????????

IniEntriesWithFirstLineEmpty
first section using System.Text.ASCIIEncoding is FirstSectionInSecondLine
first section using System.Text.Latin1Encoding is FirstSectionInSecondLine
first section using System.Text.UTF7Encoding is
first section using System.Text.UTF8Encoding is FirstSectionInSecondLine
first section using System.Text.UTF32Encoding is FirstSectionInSecondLin????????

程序:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace TestIniRead
{
    internal class Program
    {
        [DllImport("kernel32.dll", EntryPoint = "GetPrivateProfileSectionNamesA")]
        private static extern int GetSectionNamesListA(
            byte[] lpszReturnBuffer,
            int nSize,
            string lpFileName);

        private static readonly string[] IniEntriesWithSectionInFirstLine = {
                                                            "[FirstSectionInFirstLine]",
                                                            "value=firsValue",
                                                            "",
                                                            "[SecondSection]",
                                                            "value=secondValue",
                                                            "",
                                                            "[ThirdSection]",
                                                            "value=secondValue",
                                                            ""
                                                        };
        private static readonly string[] IniEntriesWithFirstLineEmpty = {
                                                            "",
                                                            "[FirstSectionInSecondLine]",
                                                            "value=firsValue",
                                                            "",
                                                            "[SecondSection]",
                                                            "value=secondValue",
                                                            "",
                                                            "[ThirdSection]",
                                                            "value=secondValue",
                                                            ""
                                                        };

        private static void Main()
        {
            var fileInfo = new FileInfo("test.ini");
            Console.WriteLine("IniEntriesWithSectionInFirstLine");
            TestEncodings(fileInfo, IniEntriesWithSectionInFirstLine);
            Console.WriteLine("");
            Console.WriteLine("IniEntriesWithFirstLineEmpty");
            TestEncodings(fileInfo, IniEntriesWithFirstLineEmpty);
            Console.ReadLine();
        }

        private static void TestEncodings(FileInfo fileInfo, IEnumerable<string> iniEntries)
        {
            TestEncoding(fileInfo, iniEntries, Encoding.ASCII);
            TestEncoding(fileInfo, iniEntries, Encoding.GetEncoding("ISO-8859-1"));
            TestEncoding(fileInfo, iniEntries, Encoding.UTF7);
            TestEncoding(fileInfo, iniEntries, Encoding.UTF8);
            TestEncoding(fileInfo, iniEntries, Encoding.UTF32);
        }

        private static void TestEncoding(FileInfo fileInfo, IEnumerable<string> iniEntries, Encoding encoding)
        {
            CreateIniFile(fileInfo, iniEntries, encoding);
            if (fileInfo.Exists)
            {
                var buffer = new byte[fileInfo.Length];
                GetSectionNamesListA(buffer, (int) fileInfo.Length, fileInfo.FullName);
                String s = encoding.GetString(buffer);
                String[] names = s.Split('\0');

                Console.WriteLine("first section using {0} is {1}", encoding, names[0]);
            }
        }

        private static void CreateIniFile(FileSystemInfo fileInfo, IEnumerable<string> iniEntries, Encoding encoding)
        {
            using (var sw = new StreamWriter(File.Open(fileInfo.FullName, FileMode.Create), encoding))
            {
                foreach (string line in iniEntries)
                {
                    sw.WriteLine(line);
                }
            }
        }
    }
}

对前三个答案的反应:

你当然是对的。我应该使用GetPrivateProfileSectionNamesW来表示Unicode文件。我提供了一种方法来获取IniFile的编码并相应地使用A或W.问题保持不变。该功能没有获得第一部分。以下是仅针对UTF8的新代码。

我得到了什么:

IniEntriesWithSectionInFirstLine
first section using System.Text.UTF8Encoding is SecondSection

程序:

using System;                                                                                                         
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace TestIniRead
{
    internal class Program
    {
        [DllImport("kernel32.dll", EntryPoint = "GetPrivateProfileSectionNamesA")]
        private static extern int GetSectionNamesListA(
                byte[] lpszReturnBuffer,
                int nSize,
                string lpFileName);

        [DllImport("kernel32", EntryPoint = "GetPrivateProfileSectionNamesW", CharSet = CharSet.Unicode)]
        private static extern int GetSectionNames
            (
            [MarshalAs(UnmanagedType.LPWStr)] string szBuffer,
            int nlen,
            string filename
            );

        private static readonly string[] IniEntriesWithSectionInFirstLine = {
                                                                "[FirstSectionInFirstLine]",
                                                                "value=firsValue",
                                                                "",
                                                                "[SecondSection]",
                                                                "value=secondValue",
                                                                "",
                                                                "[ThirdSection]",
                                                                "value=secondValue",
                                                                ""
                                                        };

        private static void Main()
        {
            var fileInfo = new FileInfo("test.ini");
            Console.WriteLine("IniEntriesWithSectionInFirstLine");
            TestEncodings(fileInfo, IniEntriesWithSectionInFirstLine);
            Console.WriteLine("");
            Console.ReadLine();
        }

        private static void TestEncodings(FileInfo fileInfo, IEnumerable<string> iniEntries)
        {
            TestEncoding(fileInfo, iniEntries, Encoding.UTF8);
        }

        private static readonly char[] separator = { '\0' };

        private static void TestEncoding(FileInfo fileInfo, IEnumerable<string> iniEntries, Encoding encoding)
        {
            CreateIniFile(fileInfo, iniEntries, encoding);
            if (fileInfo.Exists)
            {
                int len = (int)fileInfo.Length;
                var buffer = new string('\0', len);
                int nlen = GetSectionNames(buffer, len, fileInfo.FullName);
                if (nlen <= 0)
                {
                    Environment.Exit(nlen);
                }

                String[] names = buffer.Substring(0, nlen).Split(separator);
                Console.WriteLine("first section using {0} is {1}", encoding, names[0]);
            }
        }

        private static void CreateIniFile
            (
            FileSystemInfo fileInfo, 
            IEnumerable<string> iniEntries, 
            Encoding encoding)
        {
            using (var sw = new StreamWriter(File.Open(fileInfo.FullName, FileMode.Create), encoding))
            {
                foreach (string line in iniEntries)
                {
                    sw.WriteLine(line);
                }
            }
        }
    }
}

3 个答案:

答案 0 :(得分:1)

unicode文件的前几个字节可以包含字节顺序标记。您使用的任何文本编辑器都是保存unicode文件并包含字节顺序标记。这些会混淆API函数。

您是否尝试过调用GetPrivateProfileSectionNamesW? (A表示API函数的ANSI版本,宽表示W表示Unicode版本)

或者您可以设置文本编辑器以保存没有字节顺序标记的文件。

答案 1 :(得分:0)

  1. 您是否尝试过GetPrivateProfileSectionNamesW
  2. 您能确保ini文件以ASCII格式存储吗?从MSDN文档:

      

    注意此功能仅用于与16位基于Windows的应用程序兼容。

  3. .NET settings files 优于INI文件。如果您没有编写与遗留系统互操作的内容,我强烈建议您使用新方法。

答案 2 :(得分:0)

我实际上看到了同样的事情,但没有进行测试(我只是确保在ini文件的开头有一个空行)。

我最初使用.NET框架中的IO函数编写了inifile,当用oldfashion C ++编写的另一个程序读取它时,第一行丢失了。我最终改变我的.NET代码以使用ISO-8859-1编码,这可能是在unicode出现之前最接近基本文本文件编写的方式...... .NET中的默认编码是UTF8。 在许多情况下,Encodings.ASCII可能是正常的,但它只包括前127个字符。

在大多数情况下,我认为Encodings.Default会很好用,因为这代表了runnning windows实例上使用的默认代码页,在我的情况下(可能在你的情况下)映射到ISO-8859- 1编码。在世界的其他地方,它将映射到ISO-8859标准的其他子集。