有一个安卓手机导出的通讯录文件是.vcf格式的,想把这里面的联系人都提取出来,转换成Excel表格,网上有转换工具,不过吧是收费的,
看了一下Vcf文件还是很有规律的,感觉使用Io流读取信息,然后生成Excel问题还是不大的,我这里只提取了简单的名字和手机号码,应该可以有更多的信息 比如联系地址,单位等
首先创建一个maven工程 主要是导出Excel要用第三方jar包
1 <dependency> 2 <groupId>cn.hutoolgroupId> 3 <artifactId>hutool-allartifactId> 4 <version>5.0.6version> 5 dependency> 6 7 <dependency> 8 <groupId>org.apache.poigroupId> 9 <artifactId>poi-ooxmlartifactId> 10 <version>3.17version> 11 dependency>
一个是hutoll工具类框架,另外一个是Apache的处理Excel的POI
然后把代码贴出来
1 import cn.hutool.poi.excel.ExcelUtil; 2 import cn.hutool.poi.excel.ExcelWriter; 3 4 import java.io.*; 5 import java.util.ArrayList; 6 import java.util.Arrays; 7 import java.util.List; 8 9 /** 10 * @Description: 读取Vcf文件并转换为Excel 11 * @Author: Tan 12 * @CreateDate: 2020/2/5 13 **/ 14 public class VcfToExcel { 15 public static void main(String[] args) throws Exception { 16 long start=System.currentTimeMillis(); 17 //读取vcf文件 18 BufferedReader bufferedReader=new BufferedReader(new FileReader("vcf文件路径")); 19 //计数器 统计当前有多少记录 20 int count=0; 21 //创建导出Excel数据集合 22 List> exportList=new ArrayList<>(); 23 //添加一行 算标题 第一行 24 exportList.add(Arrays.asList("编号","姓名","手机号码")); 25 //读取的信息 26 String info; 27 //循环读取 28 while ((info=bufferedReader.readLine())!=null){ 29 //读取到的这一行以FN开头 代表名字 30 if(info.startsWith("FN")){ 31 //截取名字编码部分 32 String name=info.substring(info.indexOf(":")+1); 33 //名字编码的下一行为手机号也可能是名字编码的剩余字符 34 String phone=bufferedReader.readLine(); 35 //判断是否是=开头 如果是就是名字编码的剩余部分,也拼接到名字,下一行就是手机号 36 if(phone.startsWith("=")){ 37 name+=phone.substring(1); 38 phone=bufferedReader.readLine(); 39 }else if("".equals(phone)){ 40 phone=bufferedReader.readLine(); 41 } 42 //截取手机号 43 phone=phone.substring(phone.indexOf(":")+1); 44 45 //判断名字编码最后一位是否是= 如果是要删除掉 46 if(name.charAt(name.length()-1)==61){ 47 name= name.substring(0,name.length()-1); 48 } 49 //将编号 名字进行解码 和手机号 添加到导出数据 50 exportList.add(Arrays.asList(Integer.toString(++count),qpDecoding(name),phone)); 51 } 52 53 } 54 //关闭缓存流 55 bufferedReader.close(); 56 57 //创建hutool工具类的写Excel对象 58 ExcelWriter writer = ExcelUtil.getWriter("导出Excel的路径.xlsx"); 59 60 //写入数据 生成Excel 61 writer.write(exportList, true); 62 63 //关闭writer,释放内存 64 writer.close(); 65 66 System.out.println("生成完毕,耗费时间 "+(System.currentTimeMillis()-start)); 67 68 } 69 70 71 72 73 //解码方法 如果抛出数组越界异常 可能是数据不规范 检查解码字符串 74 public final static String qpDecoding(String str) 75 { 76 if (str == null) 77 { 78 return ""; 79 } 80 try 81 { 82 StringBuffer sb = new StringBuffer(str); 83 for (int i = 0; i < sb.length(); i++) 84 { 85 if (sb.charAt(i) == '\n' && sb.charAt(i - 1) == '=') 86 { 87 // 解码这个地方也要修改一下 88 // sb.deleteCharAt(i); 89 sb.deleteCharAt(i - 1); 90 } 91 } 92 str = sb.toString(); 93 byte[] bytes = str.getBytes("US-ASCII"); 94 for (int i = 0; i < bytes.length; i++) 95 { 96 byte b = bytes[i]; 97 if (b != 95) 98 { 99 bytes[i] = b; 100 } 101 else 102 { 103 bytes[i] = 32; 104 } 105 } 106 if (bytes == null) 107 { 108 return ""; 109 } 110 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 111 for (int i = 0; i < bytes.length; i++) 112 { 113 int b = bytes[i]; 114 if (b == '=') 115 { 116 try 117 { 118 int u = Character.digit((char) bytes[++i], 16); 119 int l = Character.digit((char) bytes[++i], 16); 120 if (u == -1 || l == -1) 121 { 122 continue; 123 } 124 buffer.write((char) ((u << 4) + l)); 125 } 126 catch (ArrayIndexOutOfBoundsException e) 127 { 128 e.printStackTrace(); 129 } 130 } 131 else 132 { 133 buffer.write(b); 134 } 135 } 136 return new String(buffer.toByteArray(), "UTF-8"); 137 } 138 catch (Exception e) 139 { 140 e.printStackTrace(); 141 return ""; 142 } 143 } 144 145 }
主要问题就在于 我这个vcf文件其中名字的数据并不是直接是中文的而是一个特殊的QUOTED-PRINTABLE编码
数据类似这样 =E5=BC=A0=E4=B8=89 所以需要提取到这个编码的字符串 然后调用我这个qpDecoding()方法进行解码
就这样,希望可以帮助到有需要的人