最近要实现一个用c#导出安卓电话本的功能,即*.vcf格式的电话本文件,网上查了很长时间,发现有说用csv导出的,excel导出的基本都是借助工具去导出,没有查到用响应的代码导出电话本的方式。经过一番周折,最终还是顺利的导出了想要的数据:
1.首先我们了解一下.vcf格式的文件是什么,.vcf是微软自带的通讯录vCard文件的后缀名,其实通俗来讲也只是个文本文件,即:你只需要使用txt按照正确的vCard文件的格式编写一段脚本,改一下后缀名就可以得到一个名片。代码如下:
public static void CreateCard()
{
FileStream fs = new FileStream(@"D:/a.vcf", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("BEGIN:VCARD");
sw.WriteLine("VERSION:2.1");
sw.WriteLine("N;CHARSET=UTF-8;ENCODING=QUOTED- PRINTABLE:"+"六七");
sw.WriteLine("TEL;CELL:153 2913 3892");
sw.WriteLine("END:VCARD");
sw.Flush();
sw.Close();
fs.Close();;
}
————————————————————————————
2.这样在D盘你就能看到一个名片格式的vcf文件,但是点击开文件后发现手机号码是正常的,名称的中文出现乱码了。这是因为名片格式使用了Quoted-Printable方式进行编码。网上查了下Quoted-Printable编码定义,其实很简单,就是将要编码的文字转换成byte字节流,然后使用十六进制的char型和“=”联合表达出来,如=0C表示12。下面提供编码及解码的方式:
Quoted-Printable编码
public static string EncodeQuotedPrintable(string value)
{
if (string.IsNullOrEmpty(value))
return value;
StringBuilder builder = new StringBuilder();
byte[] bytes = Encoding.UTF8.GetBytes(value);
foreach (byte v in bytes)
{
if ((v == 9) || ((v >= 32) && (v <= 60)) || ((v >= 62) && (v <= 126)))
{
builder.Append(Convert.ToChar(v));
}
else
{
builder.Append('=');
builder.Append(v.ToString("X2"));
}
}
char lastChar = builder[builder.Length - 1];
if (char.IsWhiteSpace(lastChar))
{
builder.Remove(builder.Length - 1, 1);
builder.Append('=');
builder.Append(((int)lastChar).ToString("X2"));
}
return builder.ToString();
}
Quoted-Printable解码
public static string DecodeQuotedPrintable(string input, string charSet)
{
Encoding enc;
try
{
enc = Encoding.GetEncoding(charSet);
}
catch
{
enc = new UTF8Encoding();
}
var occurences = new Regex(@"(=[0-9A-Z]{2}){1,}", RegexOptions.Multiline);
var matches = occurences.Matches(input);
foreach (Match match in matches)
{
try
{
byte[] b = new byte[match.Groups[0].Value.Length / 3];
for (int i = 0; i < match.Groups[0].Value.Length / 3; i++)
{
b[i] = byte.Parse(match.Groups[0].Value.Substring(i * 3 + 1, 2), System.Globalization.NumberStyles.AllowHexSpecifier);
}
char[] hexChar = enc.GetChars(b);
input = input.Replace(match.Groups[0].Value, new String(hexChar));
}
catch
{ ;}
}
input = input.Replace("?=", "").Replace("\r\n", "");
return input;
}
3.通过第2步我们就能将汉字转换成正确的Quoted-Printable编码方式了,这样我们最终修改第1步中的代码,将汉字部分使用Quoted-Printable进行编码
public static void CreateCard()
{
FileStream fs = new FileStream(@"D:/a.vcf", FileMode.Create);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("BEGIN:VCARD");
sw.WriteLine("VERSION:2.1");
sw.WriteLine("N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"+EncodeQuotedPrintable("六七"));
sw.WriteLine("TEL;CELL:153 2913 3892");
sw.WriteLine("END:VCARD");
sw.Flush();
sw.Close();
fs.Close();;
}
最终,我们在D盘得到了一个正确的名片,接下来导入安卓手机使用通讯录打开,这是中文显示的就是正常的六七,但是这个编码格式在pc端是不可用的,中文依旧乱码,pc端使用的是ascii编码方式,详情可自行研究。