Samsung Galaxy S6 可导入的 vCard 的 format/version/encoding 限制是什么

What is format/version/encoding limitations of vCards importable by Samsung Galaxy S6

我在尝试将使用 vCard 格式的联系人导入 Samsung Galaxy S6 时遇到问题 - see here

我正在使用以下 C# 代码创建 vCard 文件:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Thought.vCards; //https://www.nuget.org/packages/Thought.vCards/

namespace VCardGen
{
    class Program
    {
        const string INPUT_FILE = @"C:\VSProjects\VCardGen\in.txt";
        const string OUTPUT_FILE = @"C:\VSProjects\VCardGen\Files5\{0}.vcf";
        //What encoding comes here? This worked but national characters displayed as ?
        static Encoding ENCODING = Encoding.GetEncoding("Windows-1250");

        /// <summary>
        /// Removes special characters
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        static String RemoveDiacritics(String s)
        {
            String normalizedString = s.Normalize(NormalizationForm.FormD);
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < normalizedString.Length; i++)
            {
                Char c = normalizedString[i];
                if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark && CharUnicodeInfo.GetUnicodeCategory(c)!=UnicodeCategory.OtherSymbol)
                    stringBuilder.Append(c);
            }
            return stringBuilder.ToString();
        }

        /// <summary>
        /// Saves one vCard
        /// </summary>
        /// <param name="c"></param>
        static void SaveVCard(vCard c, Encoding e)
        {
            if (c == null) return;
            string fn = RemoveDiacritics(c.FamilyName + c.GivenName).Trim().Replace(" ", ""); ;
            vCardStandardWriter writer = new vCardStandardWriter();
            {
                writer.EmbedInternetImages = false;
                writer.EmbedLocalImages = false;
                writer.Options = vCardStandardWriterOptions.IgnoreCommas;
                using (var file = File.OpenWrite(String.Format(OUTPUT_FILE, fn)))
                using (var fwriter = new StreamWriter(file, e))
                {
                    writer.Write(c, fwriter);
                }
                writer = null;
            }
        }

        static void Main(string[] args)
        {
            //Load file outputed by Qontact
            string text = System.IO.File.ReadAllText(INPUT_FILE, ENCODING);
            List<string> l = text.Split('\n').ToList();
            vCard c= null;

            //Process Qontact file line by line
            foreach (string s in l)
            {
                string x = s.Trim();
                if (x.Length == 0) continue;
                if (x.StartsWith("-"))
                {
                    SaveVCard(c,ENCODING);
                    string[] np = x.Substring(1).Split(',');
                    c = new vCard();
                    c.FamilyName = np[0].Trim();
                    if (np.Length>1) c.GivenName = np[1].Trim();
                }
                else if (x.StartsWith("NAME: "))
                    c.DisplayName = x.Replace("NAME: ", "").Trim() ;                    
                else if (x.StartsWith("MOB: "))
                    c.Phones.Add(new vCardPhone(x.Replace("MOB: ", "").Trim(), vCardPhoneTypes.Cellular));
                else if (x.StartsWith("ORG:"))
                    c.Organization = x.Replace("ORG:", "").Trim();
                else if (x.StartsWith("ADDR:"))
                {
                    string n = x.Replace("ADDR:", "");
                    vCardDeliveryAddress a = new vCardDeliveryAddress();
                    a.Street = n.Trim();
                    c.DeliveryAddresses.Add(a);
                }
                else if (x.StartsWith("EMAIL:"))
                    c.EmailAddresses.Add(new vCardEmailAddress(x.Replace("EMAIL:", "").Trim()));
                else if (x.StartsWith("HOME :"))
                    c.Phones.Add(new vCardPhone(x.Replace("HOME :", "").Trim(), vCardPhoneTypes.Home));
                else if (x.StartsWith("TEL:"))
                    c.Phones.Add(new vCardPhone(x.Replace("TEL:", "").Trim(), vCardPhoneTypes.Work));                
            }
            SaveVCard(c, ENCODING);
        }
    }
}

我有一个问题,当我使用编码 Encoding.GetEncoding("Windows-1250") 时,vCards 可以很好地导入 phone,但所有国家特定字符都被转换为 ? .

当我使用 Encoding.UTF8 时,它会产生如下内容:

BEGIN:VCARD
VERSION:3.0
NAME:XXXXX GĂĽnzel
N:GĂĽnzel;XXXXX;;;
TEL;CELL:+XXXXXXXXXX
END:VCARD

导入失败。

当我使用 Windows-1250 时,它会产生如下内容:

BEGIN:VCARD
VERSION:3.0
NAME:XXXX Günzel
N:Günzel;XXXXX;;;
TEL;CELL:+XXXXXXXXX
END:VCARD

导入成功,但没有国家特定的字符。

导入文件如下所示:

-AAA Taxi
MOB: 11111111111


-Adam
MOB: 1111111111111
EMAIL:info@aaaaa.aa

我总是在 运行 程序之前用 PSPad 文本编辑器将它转换为相应的编码。

我应该解决什么问题才能生成具有正确字符编码的可导入 vCard,并且在 Samsung Galaxy S6 上显示正常?

当你使用内置常量Encoding.UTF8时,它总是在开头添加一个字节顺序标记。这就是导致问题的原因。使用 false 作为参数创建 UTF8Encoding class 的新实例。然后你会得到它以UTF8编码,但开头没有写字节顺序标记。