vcards(vcf)文件转Excel

有一个安卓手机导出的通讯录文件是.vcf格式的,想把这里面的联系人都提取出来,转换成Excel表格,网上有转换工具,不过吧是收费的,

看了一下Vcf文件还是很有规律的,感觉使用Io流读取信息,然后生成Excel问题还是不大的,我这里只提取了简单的名字和手机号码,应该可以有更多的信息 比如联系地址,单位等

首先创建一个maven工程 主要是导出Excel要用第三方jar包

 1           <dependency>
 2             <groupId>cn.hutool</groupId>
 3             <artifactId>hutool-all</artifactId>
 4             <version>5.0.6</version>
 5         </dependency>
 6 
 7         <dependency>
 8             <groupId>org.apache.poi</groupId>
 9             <artifactId>poi-ooxml</artifactId>
10             <version>3.17</version>
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<List<String>> 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()方法进行解码

就这样,希望可以帮助到有需要的人

posted @ 2020-02-06 12:43  沙漠里的橘子皮  阅读(4528)  评论(0编辑  收藏  举报