C#生成vCard文件 C#如何创建.vcf电子名片文件

2次阅读

用 stringbuilder 拼接 vcard 4.0 最稳妥,需严格遵循字段顺序、utf-8 编码、crlf 换行、ASCII 文件名及非空字段省略规则。

C#生成vCard文件 C#如何创建.vcf电子名片文件

StringBuilder 拼接 vCard 4.0 标准文本最稳妥

vCard 不是二进制格式,本质是纯文本(UTF-8 编码),C# 里直接用 StringBuilder 按规范拼字符串即可,无需第三方库。关键在于严格遵循字段顺序、转义规则和换行符(rn)。常见错误是漏掉 VERSION:3.0END:VCARD,或对含逗号/分号的姓名、邮箱未做 QUOTED-PRINTABLE 编码(其实 vCard 4.0 推荐用 UTF-8 + 行折叠,但多数手机仍兼容 3.0 的简单转义)。

实操建议:

  • 开头固定写 BEGIN:VCARDrnVERSION:3.0rnios/android 识别最稳)
  • 姓名字段用 N:Last;First;Middle;;rnFN:First Middle Lastrn,注意分号分隔姓/名/中间名,末尾两个分号不能少
  • 邮箱、电话必须带类型参数,如 EMAIL;TYPE=WORK:dev@example.comrnTEL;TYPE=CELL:+8613800138000rn
  • 地址字段用 ADR;TYPE=HOME:;;Street 123;City;State;100000;CNrn,各段用分号分隔,空段留空但分号保留
  • 所有值含换行、逗号、分号时,需用 = 转义:换行→=0D=0A,逗号→=2C,分号→=3B(但实际中多数读取器容忍不转义,仅当解析失败时再加)

File.WriteAllText 保存时必须指定 Encoding.UTF8

Windows 默认 File.WriteAllText 用 UTF-8 without bom,这恰好是 vCard 要求的编码。但若手动指定 Encoding.defaultEncoding.GetEncoding("GB2312"),中文会乱码——微信、iphone 短信里点开直接显示问号。

实操建议:

  • 保存路径用 .vcf 后缀,如 path = @"C:tempcontact.vcf"
  • 调用 File.WriteAllText(path, vcardContent, Encoding.UTF8),显式传参,别依赖默认
  • 避免用 StreamWriter 且未设 Encoding,容易隐式走系统区域设置
  • 生成后可用记事本“另存为”确认编码是否为 UTF-8(无签名),或用 VS Code 底部状态栏看编码标识

微信/QQ/邮件附件发 vCard,文件名别含空格或中文

移动端微信转发 .vcf 文件时,如果文件名是 张三名片.vcfmy contact.vcf,iOS 往往无法识别为电子名片,点开就当普通文本;Android 部分机型也会提示“不支持的文件类型”。根本原因是 MIME 类型协商失败,而文件名是触发条件之一。

实操建议:

  • 文件名只用 ASCII 字母、数字、下划线、短横线,如 contact_zhangsan.vcfuser_123.vcf
  • 发送邮件时,在 Attachment 中显式设置 ContentTypenew ContentType("text/vcard")
  • 微信内测试:先发给自己,点开确认出现“添加到通讯录”按钮,而非“用其他应用打开”
  • 若需批量生成,文件名用 GUID 哈希前 8 位(如 5a7b2c1e.vcf),彻底规避命名问题

字段缺失时不要留空行,用注释代替或直接省略

vCard 解析器对空字段敏感。比如写了 TEL;rn(后面没值),某些 Android 厂商定制 ROM 会崩溃;又或者 PHOTO; 后跟空值,iOS 可能拒绝导入。这不是标准问题,而是实现差异。

实操建议:

  • 只写业务上真实存在的字段,不确定的(如 ORGTITLE)直接跳过,别留占位符
  • 若需标记“该字段暂无”,用 X-NO-ORG:1rn 这类自定义扩展字段(以 X- 开头),标准解析器会忽略
  • 照片不嵌入 base64(体积大、易出错),优先用 PHOTO;VALUE=URI:https://example.com/photo.jpgrn
  • 测试时用 iOS 自带“通讯录”App 导入,它报错最严格,能提前暴露字段格式问题

vCard 表面简单,但跨平台兼容性卡点全在细节:换行符必须 rn、编码必须 UTF-8 无 BOM、文件名必须 ASCII、字段值为空就干脆不写——这些地方错一个,用户点开就失败,还很难定位。

text=ZqhQzanResources