java解析 VCF文件导入导出数据库
前几天,客户要求开发个小功能,就是把手机的VCF电话薄文件导出来后,可以导入数据库,然后从数据库出来的记录,同样可以生成vcf文件,并且地手机导入后可以成为有用电话薄.(vcf文件内容格式另外有介绍)
大家可以看看http://sourceforge.net/projects/mime-dir-j/这个开源的,前几天还上不了个网站(我是用代理上的),这几天好像是可以了,我是自己看了下源码.然后写了下,
在java中生成vcf文件,我是在Servlet中用文件流做的部份代码如下 :
response.setHeader("Content-Disposition","attachment; filename="+ new String(bean.getTrueName().getBytes("GBK"), "ISO8859-1" )+".vcf");
try{
java.io.PrintWriter bufout=response.getWriter();
bufout.write("BEGIN:VCARD");
bufout.write("\r\n");
bufout.write("VERSION:2.1");
bufout.write("\r\n");
bufout.write("N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:"+AddressServlet.qpEncodeing(bean.getTrueName())+";");
bufout.write("\r\n");
if(""!=bean.getMobile()&&bean.getMobile()!=null){
bufout.write("TEL;CELL:"+bean.getMobile()+"");
bufout.write("\r\n");
}
if(""!=bean.getWorkMobile()&&bean.getWorkMobile()!=null){
bufout.write("TEL;WORK:"+bean.getWorkMobile()+"");
bufout.write("\r\n");
}
if(""!=bean.getTelephone()&&bean.getTelephone()!=null){
bufout.write("TEL;HOME:"+bean.getTelephone()+"");
bufout.write("\r\n");
}
if(""!=bean.getEmail()&&bean.getEmail()!=null){
bufout.write("EMAIL:"+bean.getEmail()+"");
bufout.write("\r\n");
}
bufout.write("END:VCARD");
bufout.write("\r\n");
response.getOutputStream().flush();
response.getOutputStream().close();
}
catch(IOException E){
System.out.println("vcfexport发生I/O错误!");
}
qpEncodeing()这个方法是专门编码成这种格式的(http://www.blogjava.net/sundc/archive/2008/08/04/219863.html).
2.从本地上传后导入到DB,我也是在Servlet实现的
FileItem fi=null;
try {
FileUpload fu = new FileUpload();
// 设置最大文件尺寸,这里是2MB
fu.setSizeMax(2097152);
// 得到所有的文件:
DiskFileItemFactory factory = new DiskFileItemFactory();
fu.setFileItemFactory(factory);
List fileItems = fu.parseRequest(requestContext);
Iterator i = fileItems.iterator();
while(i.hasNext()) {
fi= (FileItem)i.next();
// 获得文件名,这个文件名包括路径:
String fileName = fi.getName();
if(fi.getSize()>2097152){
return "文件太大";
}
if(fileName==null){
return "文件错误";
}
String fileExt=StringUtils.getFileExt(fileName).toLowerCase();
if (fileExt.toLowerCase().equals("vcf")){
Properties p=this.createProperties();
try {
ArrayList li = this.importVCFFileContact(fi.getInputStream(), p);
if(li==null||li.size()==0){
return "导入记录0条,可能是导入文件内容格式不正确";
}
this.addAddresses(li);
return "1";
} catch (IOException e) {
return "文件格式发生错误";
}
}
else{
return "不是vcf文件";
}
}
}
catch(Exception e) {
if(e.getMessage().indexOf("maximum")>0){
return "导入文件发生错误,文件大于2M";
}
log.debug(e.getMessage());
return "导入文件发生错误"+e.getMessage();
}
finally{
try{
//删除临时文件
fi.delete();
}
catch (Exception e) {
// TODO: handle exception
}
}
return "发生错误";
}
这个上传中用到的代码.下面是把VCF文件解析成bean对象
/**
* 导入联系人
* @param in
* @throws SystemException
*/
public ArrayList importVCFFileContact(InputStream in,Properties pp) throws SystemException{
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
Document document = new DocumentImpl();
BufferedWriter writer = null;
String line;
StringBuffer bu=new StringBuffer();
while ((line = DecorGroup.nextLine(reader)) != null) {
bu.append(line+"\r\n");
}
Pattern p=Pattern.compile("BEGIN:VCARD(\\r\\n)([\\s\\S\\r\\n\\.]*?)END:VCARD");//分组,
Matcher m=p.matcher(bu.toString());
while(m.find()){
AddressBean be=new AddressBean();
be.setCateId(gb.getId());
be.setUserId(gb.getUserId());
String str=m.group(0);
//姓名
Pattern pn=Pattern.compile("N;([\\s\\S\\r\\n\\.]*?)([\\r\\n])");//分组,
Matcher mn=pn.matcher(m.group(0));
while(mn.find()){
String name="";
if(mn.group(1).indexOf("ENCODING=QUOTED-PRINTABLE")>-1){
name=mn.group(1).substring(mn.group(1).indexOf("ENCODING=QUOTED-PRINTABLE:")+"ENCODING=QUOTED-PRINTABLE:".length());
name=name.substring(name.indexOf(":")+1);
if(name.indexOf(";")>-1){
name=name.substring(0,name.indexOf(";"));
be.setTrueName(AddressServlet.qpDecoding(name));
}
else{
be.setTrueName(AddressServlet.qpDecoding(name));
}
}
else{
Pattern pnn=Pattern.compile("CHARSET=([A-Za-z0-9-]*?):");
Matcher mnn=pnn.matcher(mn.group(1));
while(mnn.find()){
name=mn.group(1).substring(mn.group(1).indexOf(mnn.group(0))+mnn.group(0).length());
be.setTrueName(name);
}
}
}
if(be.getTrueName().length()>20){
return null;
}
String cell="";
Pattern p1=Pattern.compile("TEL;CELL:\\d*");//分组,
Matcher m1=p1.matcher(str);
while(m1.find()){
cell=m1.group(0).substring(m1.group(0).indexOf("TEL;CELL:")+"TEL;CELL:".length());
}
be.setMobile(cell);
if(be.getMobile().length()>13){
return null;
}
String work="";
Pattern p2=Pattern.compile("TEL;WORK:\\d*");//分组,
Matcher m2=p2.matcher(str);
while(m2.find()){
work=m2.group(0).substring(m2.group(0).indexOf("TEL;WORK:")+"TEL;WORK:".length());
}
be.setWorkMobile(work);
if(be.getWorkMobile().length()>13){
return null;
}
String home="";
Pattern p3=Pattern.compile("TEL;HOME:\\d*");//分组,
Matcher m3=p3.matcher(str);
while(m3.find()){
home=m3.group(0).substring(m3.group(0).indexOf("TEL;HOME:")+"TEL;HOME:".length());
}
be.setTelephone(home);
if(be.getTelephone().length()>13){
return null;
}
String email="";
Pattern p4=Pattern.compile("\\w+(\\.\\w+)*@\\w+(\\.\\w+)+");//分组,
Matcher m4=p4.matcher(str);
while(m4.find()){
email=m4.group(0);
}
be.setEmail(email);
}
reader.close();
} catch (Exception e) {
log.debug(e.getMessage());
throw new SystemException("对不起,系统忙,请梢后再试!");
}
return abs;
}
以下是源码中自代的方法,我COPY过来就用了
public static String nextLine(BufferedReader reader) throws IOException {
String line;
String nextLine;
do {
line = reader.readLine();
if (line == null) return null;
} while (line.length() == 0);
// Evolution style line folding
while (line.endsWith("=")) {
line = line.substring(0, line.length() - 1);
line += reader.readLine();
}
// RFC 2425 line folding
reader.mark(1000);
nextLine = reader.readLine();
if ((nextLine != null)
&& (nextLine.length() > 0)
&& ((nextLine.charAt(0) == 0x20) // white space
|| (nextLine.charAt(0) == 0x09))) { // tab
line += nextLine.substring(1);
} else {
reader.reset();
}
line = line.trim();
return line;
}
在这里要提醒大家,有的手机的电话薄可能字选项会多一点.所以,我在这做的是 姓名 手机号码 电话 工作电话 Email这几个大家手机都会有的. 程序通过诺基亚,三星(SAMSUNG),摩托罗拉(MOTO),还有国产波导,哈哈.....
如有问题,大家可以评论...