因本人比较懒,单位上有八十多号人,不想一个个去添加联系人,但现有的一些批量添加联系人的方法貌似都不怎么好用,故特意写了个针对华为Play 4t Pro批量添加联系人的软件;本软件已确认支持华为Play 4t Pro手机,至于华为其他型号或其他品牌手机暂未测试;华为品牌的手机可以试试,成功的概率估计会好高。
以下是关键代码,需要完整代码或软件的请留言或发邮件1406133926@qq.com联系,看到了会回复,实在等不及的可以加QQ;
步骤1、2用于解析已有的联系人的.vcf文件,并生成.xls文件,便于个人做数据去重等操作,不需要的可以直接跳过;
步骤3为将有联系人信息的.xls文件加密成.txt文件;将步骤3生成的.txt文件直接改后缀为.vcf后,直接导入手机中,手机会自动识别。
1、以下代码用于解析已将的.vcf联系人直接改后缀成.txt文件;
/// <summary>
/// 读取,解析.vcf直接改后缀成的.txt文件,将名片信息保存在DataTable中
/// </summary>
/// <param name="file_Path_txt">将.vcf直接改后缀成.txt的文件路径</param>
private DataTable Analysis_vcf(string file_Path_txt)
{
#region 创建通讯录.xls文件列名
System.Data.DataTable dt = new System.Data.DataTable();
DataColumn name = new DataColumn("姓名", Type.GetType("System.String"));
DataColumn cell = new DataColumn("手机", Type.GetType("System.String"));
DataColumn work = new DataColumn("座机", Type.GetType("System.String"));
DataColumn email = new DataColumn("邮箱", Type.GetType("System.String"));
DataColumn org = new DataColumn("单位", Type.GetType("System.String"));
DataColumn title = new DataColumn("职位", Type.GetType("System.String"));
DataColumn note = new DataColumn("备注", Type.GetType("System.String"));
DataColumn group = new DataColumn("群组", Type.GetType("System.String"));
dt.Columns.Add(name);
dt.Columns.Add(cell);
dt.Columns.Add(work);
dt.Columns.Add(email);
dt.Columns.Add(org);
dt.Columns.Add(title);
dt.Columns.Add(note);
dt.Columns.Add(group);
#endregion
#region 解析.txt通讯录文件,并保存到DataTable中
try
{
using (StreamReader sr = new StreamReader(file_Path_txt))//读取.txt文件
{
string[] STRING = { "FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:", "TEL;CELL:", "TEL;WORK:", "EMAIL;HOME :", "ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:", "TITLE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:", "NOTE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:", "X-GROUP-MEMBERSHIP:" };//存放识别字符串;分别为姓名、手机、座机、邮件、单位、职位、备注(0,4,5,6需要解码,注意:不识别英文姓名)
string[] INFOR = new string[8] { "", "", "", "","", "", "", "" };//存放空名片信息:姓名 手机 座机 邮箱 单位 职位 备注 群组
string line;
while ((line = sr.ReadLine()) != null)//按行读取.txt文件(如果数据太长,原始.vcf文件会自动换行,所以存在丢数据或解析乱码情况)
{
for (int i=0;i<STRING.Length;i++)
{
if(line.Contains (STRING[i]))
{
if (i==0 || i == 4 || i == 5 || i == 6)//姓名、单位、职位、备注,需要解码
{
if (line.Substring(STRING[i].Length).Contains("="))
{
INFOR[i] = UnHex(line.Substring(STRING[i].Length).Replace("=", "").Replace(";", ""));
}
else
{
INFOR[i] = line.Substring(STRING[i].Length).Replace(";", "");
}
}
else
{
INFOR[i] = line.Substring(STRING[i].Length).Replace("=", "").Replace(";", "");
}
break;
}
}
if (line.Contains("END:VCARD"))//结束,将读取的个人名片信息,保存到DataTable中
{
DataRow dr = dt.NewRow();
for (int i=0;i<INFOR.Length;i++)
{
dr[i] = INFOR[i].ToString();
}
dt.Rows.Add(dr);
//清空个人名片信息,便于下次存放数据
for(int i=0;i<INFOR .Length;i++)
{
INFOR[i] = "";
}
}
return dt;
}
}
catch(Exception ex)
{
MessageBox.Show("读取解析文件错误" + ex.Message);
}
}
#endregion
}
/// <summary>
/// 将16进制字符串转换成UTF-8汉字
/// </summary>
/// <param name="hex">16进制字符串</param>
private string UnHex(string hex)
{
if (hex == null)
{
throw new ArgumentNullException("hex");
}
hex = hex.Replace(",", "");
hex = hex.Replace("\n", "");
hex = hex.Replace("\\", "");
hex = hex.Replace(" ", "");
if (hex.Length % 2 != 0)
{
hex += "20";//空格
}
//需要将 hex 转换成 byte 数组。
byte[] bytes = new byte[hex.Length / 2];
for (int i = 0; i < bytes.Length; i++)
{
try
{
//每两个字符是一个 byte。
bytes[i] = byte.Parse(hex.Substring(i * 2, 2),
System.Globalization.NumberStyles.HexNumber);
}
catch
{
// Rethrow an exception with custom message.
throw new ArgumentException("不是16进制字符串!", "hex");
}
}
System.Text.Encoding chs = System.Text.Encoding.GetEncoding("utf-8");
return chs.GetString(bytes);
}
2、解析后的DataTable数据保存到.xls文件中;
/// <summary>
/// 将DataTable中的数据,写入到Excel文件中
/// </summary>
/// <param name="dt">数据源DataTable</param>
/// <param name="FileName">文件名</param>
/// <param name="outres">存放文件路径</param>
private void Export_DataTable_TO_Excel(DataTable dt, string FileName, ref string outres)
{
if (dt.Rows.Count > 0)
{
int row = dt.Rows.Count;//设置表的行数
int col = dt.Columns .Count;//设置表的列数
DateTime beforetime = DateTime.Now;
Microsoft.Office.Interop.Excel.Application myExcel = new Microsoft.Office.Interop.Excel.Application();//创建Excel表
DateTime aftertime = DateTime.Now;
myExcel.Visible = false;
Microsoft.Office.Interop.Excel.Workbooks myWorkbooks = myExcel.Workbooks;//创建Excel工作表集合
Microsoft.Office.Interop.Excel.Workbook myWorkbook = myWorkbooks.Add(System.Reflection.Missing.Value);//创建Excel工作表
Microsoft.Office.Interop.Excel.Worksheet myWorksheet = (Microsoft.Office.Interop.Excel.Worksheet)myWorkbook.Worksheets[1];//创建Excel工作表Sheet1页
Microsoft.Office.Interop.Excel.Range myRange = myExcel.get_Range(myExcel.Cells[1, 1], myExcel.Cells[1, col]);//选择页的范 myExcel.Cells[1, 4]表示下面myhead中存入的好多哥表头的个数
object[] myhead = { "姓名", "手机", "座机", "邮箱","单位", "职务", "备注", "群组" };//设置表头,这种设置表头的方法是写死的,虽然有点笨,但是效果还是不错的
for (int i = 1; i <= col; i++)
{
Microsoft.Office.Interop.Excel.Range rngA = (Microsoft.Office.Interop.Excel.Range)myWorksheet.Columns[i, Type.Missing];//设置单元格格式
rngA.NumberFormatLocal = "@";//字符型格式
}
myRange.Value2 = myhead;
myRange = myWorksheet.get_Range("A2", System.Reflection.Missing.Value);
object[,] mydata = new object[row, col];
int m = 0;
foreach (System.Data.DataRow row2 in dt.Rows)
{
int j = 0;
foreach (System.Data.DataColumn column in dt.Columns)
{
mydata[m, j] = row2[column.ColumnName].ToString();
j = j + 1;
}
m = m + 1;
}
myRange = myRange.get_Resize(row, col);
myRange.Value2 = mydata;//把mydata数组的值存到Excel表导出
myRange.EntireColumn.AutoFit();
SaveFileDialog sfd = new SaveFileDialog();
sfd.DefaultExt = "xls";
sfd.Filter = "Excel文件(*.xls)|*.xls";
sfd.FileName = FileName;
myWorkbook.Saved = true;
if (sfd.ShowDialog() == DialogResult.OK)
{
myWorkbook.Saved = true;
myWorkbook.SaveCopyAs(sfd.FileName);
outres = "1";
}
//关闭活页簿
myWorkbook.Close(false, Type.Missing, Type.Missing);
myWorkbooks.Close();//关闭Excel
myExcel.Quit();//释放Excel资源
System.Runtime.InteropServices.Marshal.ReleaseComObject(myExcel);
myWorkbook = null;
myWorksheet = null;
myRange = null;
myExcel = null;
GC.Collect();
Process[] ps = Process.GetProcesses();
foreach (Process p in ps)
{
if (p.ProcessName.ToLower().Equals("excel"))
{
DateTime starttime = p.StartTime;
if (starttime > beforetime && starttime < aftertime)
{
p.Kill();
}
}
}
}
else
{
outres = "0";
}
}
3、将包含个人名片信息的.xls文件,加密成.txt文件;最后可手动将.txt直接改后缀成.vcf文件,导入到手机中,即可自动识别;
/// <summary>
/// 读取Excel中的数据,并将读取的数据保存到DataTable中,数据列为:姓名、手机、座机、邮箱、单位、职务、备注、群组
/// </summary>
/// <returns></returns>
private DataTable ReadExcel()
{
//打开文件
OpenFileDialog file = new OpenFileDialog();
file.Filter = "Excel(*.xlsx)|*.xlsx|Excel(*.xls)|*.xls";
file.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
file.Multiselect = false;
if (file.ShowDialog() == DialogResult.Cancel)
return null;
//判断文件后缀
var path = file.FileName;
try
{
//连接字符串
string connstring = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + path + ";Extended Properties='Excel 8.0;HDR=NO;IMEX=1';"; // Office 07及以上版本 不能出现多余的空格 而且分号注意
//string connstring = Provider=Microsoft.JET.OLEDB.4.0;Data Source=" + path + ";Extended Properties='Excel 8.0;HDR=NO;IMEX=1';"; //Office 07以下版本
using (OleDbConnection conn = new OleDbConnection(connstring))
{
conn.Open();
DataTable sheetsName = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "Table" }); //得到所有sheet的名字
string firstSheetName = sheetsName.Rows[0][2].ToString(); //得到第一个sheet的名字
string sql = string.Format("SELECT * FROM [{0}]", firstSheetName); //查询字符串
OleDbDataAdapter ada = new OleDbDataAdapter(sql, connstring);
DataSet set = new DataSet();
ada.Fill(set);
return set.Tables[0];
}
}
catch (Exception)
{
return null;
}
}
/// <summary>
/// 将读取到通讯录信息DataTable,加密保存到.txt中
/// </summary>
/// <param name="filePath">生成的.txt文件存放的完整路径名,含后缀</param>
private void CreateText(string filePath)
{
DataTable dt = ReadExcel();
StreamWriter sw = File.AppendText(filePath);//指定路径
//StreamWriter sw = File.AppendText(Application.StartupPath + filePath);//程序根目录路径
for(int i=1;i<dt.Rows.Count;i++)//一个个个人信息写入到.txt中
{
sw.WriteLine("BEGIN:VCARD"+Environment .NewLine + "VERSION:2.1");//Play 4t Pro固定的开头样式
sw.WriteLine("N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=" + ToHex(dt.Rows[i][0].ToString()));//姓名,需要UTF-8转16进制(如果是英文名字,样式格式为“N:”,同时也不需要转码)
sw.WriteLine("FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=" + ToHex(dt.Rows[i][0].ToString()));//姓名,需要UTF-8转16进制(如果是英文名字,样式格式为“N:”,同时也不需要转码)
sw.WriteLine("TEL;CELL:" + dt.Rows[i][1].ToString());//手机
if(dt.Rows[i][2].ToString().Trim().Length >0)
{
sw.WriteLine("TEL;WORK:" + dt.Rows[i][2].ToString());//座机
}
if (dt.Rows[i][3].ToString().Trim().Length > 0)
{
sw.WriteLine("EMAIL;HOME:" + dt.Rows[i][3].ToString());//邮箱
}
if (dt.Rows[i][4].ToString().Trim().Length > 0)
{
sw.WriteLine("ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=" + ToHex(dt.Rows[i][4].ToString()));//单位,需要UTF-8转16进制(如果是英文,样式格式可能为“ORG:”,同时也不需要转码,未测试!)
}
if (dt.Rows[i][5].ToString().Trim().Length > 0)
{
sw.WriteLine("TITLE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=" + ToHex(dt.Rows[i][5].ToString()));//职务,需要UTF-8转16进制(如果是英文,样式格式可能为“ORG:”,同时也不需要转码,未测试!)
}
if (dt.Rows[i][6].ToString().Trim().Length > 0)
{
sw.WriteLine("NOTE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=" + ToHex(dt.Rows[i][6].ToString()));//备注,需要UTF-8转16进制(如果是英文,样式格式可能为“ORG:”,同时也不需要转码,未测试!)
}
if (dt.Rows[i][7].ToString().Trim().Length > 0)
{
sw.WriteLine("X-GROUP-MEMBERSHIP:" + dt.Rows[i][7].ToString());//群组
}
sw.WriteLine("END:VCARD");//Play 4t Pro固定的结束样式
}
sw.Flush();
sw.Close();
MessageBox.Show("生成.txt文件成功!");
}
/// <summary>
/// 汉字UTF-8转16进制
/// </summary>
/// <param name="s">需要转码的汉字</param>
/// <returns></returns>
private string ToHex(string s)
{
if ((s.Length % 2) != 0)
{
s += " ";//空格
//throw new ArgumentException("s is not valid chinese string!");
}
System.Text.Encoding chs = System.Text.Encoding.GetEncoding("utf-8");
byte[] bytes = chs.GetBytes(s);
string str = "";
for (int i = 0; i < bytes.Length; i++)
{
str += string.Format("{0:X}", bytes[i]);
if (i != bytes.Length - 1)
{
str += string.Format("{0}", "=");
}
}
return str.ToLower();
}