1

我在阅读具有不同编码的 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);
                }
            }
        }
    }
}

对前三个答案的反应:

你当然是对的。对于 Unicode 文件,我应该使用 GetPrivateProfileSectionNamesW。我包含了一种方法来获取 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);
                }
            }
        }
    }
}
4

3 回答 3

1

unicode 文件的前几个字节可以包含字节顺序标记。无论您使用什么文本编辑器,都可以保存 unicode 文件并包含字节顺序标记。这些会混淆 API 功能。

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

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

于 2009-07-22T11:29:37.993 回答
0
  1. 你试过GetPrivateProfileSectionNamesW吗?

  2. 你能确保ini文件以ASCII存储吗?从 MSDN 文档:

    注意提供此功能只是为了与基于 Windows 的 16 位应用程序兼容。

  3. .NET 设置文件大大优于INI 文件。如果您不编写与遗留系统互操作的东西,我强烈建议您使用新方法。

于 2009-07-22T11:30:50.567 回答
0

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

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

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

于 2009-07-22T11:34:24.647 回答