Parsing a vCard file to generate a CSV file with the required data

Off late I have been juggling between a Nokia Symbian phone and an Android phone. The issue which I was facing while I juggled between the phones is the availability of contacts across both the devices. My Android phone had all the contacts which I wanted to be transferred to the Symbian phone as well. I wasnt able to come across a tool or a software which would help me do this. So what I ended up doing is this:

  1. Backup the contacts in the Android phone using the backup option provided in the default Contacts app and then copy this created vCard file (.vcf file) to the PS.
  2. Download and install the Nokia PC Suite and connect the Symbian phone to the PC using the PC Suite.
  3. Parse the contents of .vcf file and generate a CSV fle (.csv file) into the Symbian phones using the Contacts manager option present in the PC Suite

Now that parsing a vCard file which I got from my Android phone had lot of unnecessary data like photo and in some cases contains only emails. But I am more interested in obtaining the names and the telephone numbers stored against each person. So from the huge vCard file while I am parsing I should be extracting the name and telephone numbers of the vCard. Lets take a look at the sample vCard file:

Also read:

BEGIN:VCARD
VERSION:2.1
EMAIL;PREF:only_for_iitians@yahoogroups.com
END:VCARD
BEGIN:VCARD
VERSION:2.1
EMAIL;PREF:abcxyz@indiatimes.com
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:G;Ramesh;;;
FN:Ramesh G
TEL;CELL:9145600900
EMAIL;PREF:ramesh_g19839@gmail.com
END:VCARD
BEGIN:VCARD
VERSION:2.1
N:;Abcd;;;
FN:Abcd
TEL;X-Airtel:456-12345-23
TEL;X-T24:879-284-3064
TEL;X-T1:+911234567890
TEL;X-T2:+919087654321
END:VCARD

In the above sample vCard file there are few vCards which have no telephone number in them. So while we parse this file we need to make sure we reject such vCard entries.

And the CSV file expected by the Symbian phone has lot of data elements that need to be added. Instead of providing all the details what I would be doing is to just provide last name, home number, home mobile, general number, general mobile, business number, business mobile. This way we can store atmost 6 numbers against a give person. The CSV file format expected by the Nokia PC Suite Contacts Manager is:

"Last name","General mobile","General phone","Home mobile","Home phone","Business mobile","Business phone",""
"Ramesh G","9145600900","","","","","",""
"Abcd","456-12345-23","879-284-3064","+911234567890","+919087654321","","",""

The above CSV file is the representation for the vCard file show before. My aim in this post is to show how to convert from the vCard file(shown above) into to the CSV file(shown just above). And I will do this programmatic ally by writing a parser and a generator in Java. This exercise has given me two advantages:

  1. I was able to import the contacts into my Symbian phone easily.
  2. I could spend some time doing some good coding.

Creating Parser to parse vCard data

From the above sample vCard data we can observe that:

  • The vCard begins with BEGIN:VCARD and ends with END:VCARD
  • The full name is prefixed with FN.
  • The telephone numbers are prefixed with TEL.
  • Each row contains 2 parts- the name of the data element and the value of the data element, both separated by a “:”.

Each data extracted from the vCard file is used to populate the following model class:

/**
 * The model bean to store the contact details extracted from vCard file.
 */
class MyCSVContact{
  String lastName;
  String generalMobile;
  String generalPhone;
  String homeMobile;
  String homePhone;
  String businessMobile;
  String businessPhone;

  /**
   * We support storing multiple telephone numbers against a given user.
   * So we store it in some order as given in the if condition below.
   */
  public void addTelephone(String tel){
    if ( generalMobile == null ){
      generalMobile = tel;
    }
    else if ( generalPhone == null ){
      generalPhone = tel;
    }
    else if ( homeMobile == null ){
      homeMobile = tel;
    }
    else if ( homePhone == null ){
      homePhone = tel;
    }
    else if ( businessMobile == null ){
      businessMobile = tel;
    }
    else if ( businessPhone == null ){
      businessPhone = tel;
    }
    else{
      System.out.println("Limit reached on the telephone numbers");
    }
  }

  @Override
  public String toString(){
    StringBuilder builder = new StringBuilder();
    appendToBuilder(builder, lastName,false);
    appendToBuilder(builder, generalMobile,false);
    appendToBuilder(builder, generalPhone,false);
    appendToBuilder(builder, homeMobile,false);
    appendToBuilder(builder, homePhone,false);
    appendToBuilder(builder, businessMobile,false);
    appendToBuilder(builder, businessPhone,false);
    appendToBuilder(builder, null, true);
    return builder.toString();
  }

  private void appendToBuilder(StringBuilder builder, String value, boolean last){
    if(value == null ){
      builder.append("\"").append("\"");
    }
    else{
      builder.append("\"").append(value).append("\"");
    }
    if(!last){
      builder.append(",");
    }
  }

}

Now that we have a fair idea of the format of the data present in the vCard file, now let me enumerate the step involved in parsing the data:

  1. Read the source file into a list of Strings.
  2. For each string if it indicates the beginning of the vCard then create a new instance of MyCSVContact
  3. As and when we encounter either the name or telephone number we update the instance of MyCSVContact accordingly
  4. If the end of the vCard is encountered then the instance of MyCSVContact is added to the list.

Lets look at the code:

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * Parser code for parsing the vCard file and creating a CSV file.
 */
public class VCFParser {

  public static final String BEGIN_VCARD = "BEGIN:VCARD";
  public static final String END_VCARD = "END:VCARD";
  public static final String VERSION = "VERSION:2.1";

  public static void main(String[] args) throws IOException {

    /**
     * Create a path object which holds the location of the vCard file.
     */
    Path fileLocation = Paths.get("D:\\Android Backup\\Contacts.vcf");
    if( ! Files.exists(fileLocation)){
      System.out.println("File Doesn't exist. Exiting...");
      System.exit(1);
    }

    /**
     * Create a path object which holds the directory of the CSV file to be created.
     */
    Path individualDirectory = Paths.get("D:\\Android Backup\\IndiContacts");

    if (!Files.exists(individualDirectory)) {
      Files.createDirectory(individualDirectory);
    }

    MyCSVContact csvContact = null;
    List<MyCSVContact> csvContacts = new ArrayList<>();
    boolean addToList = false;

    /**
     * 1. Reading the contents of the file into a list and iterating through it.
     */
    for (String str : Files.readAllLines(fileLocation, Charset.defaultCharset())) {

      /**
       * 2. Indicates the beginning of vCard and hence create a new instance of
       * MyCSVContact.
       */
      if (str.contains(BEGIN_VCARD)) {
        csvContact = new MyCSVContact();
        addToList = false;
      }

      /**
       * 3. Populating the instance of MyCSVContacts with the data obtained from
       * the vCard parsing.
       */
      if (csvContact != null) {
        String[] contactDetArr = str.split(":");
        if (contactDetArr.length > 1) {
          String contactDet = contactDetArr[0];
          String contactVal = contactDetArr[1];

          if(contactDet.startsWith("TEL")){
            csvContact.addTelephone(contactVal);
            addToList = true;
          }
          else if (contactDet.startsWith("FN")){
            csvContact.lastName = contactVal;
          }

        }
      }

      /**
       * 4. End of the vCard is found and hence the instance of MyCSVContact is
       * added to the list.
       */
      if (str.contains(END_VCARD)) {
        if (addToList)
        {
          csvContacts.add(csvContact);
        }
        csvContact = null;
      }
    }

    /**
     * Creating the actual CSV file.
     */
    Path androidCsvContacts = Paths.get(individualDirectory.toString(), "AndroidContacts.csv");
    if( ! Files.exists(androidCsvContacts)){
      Files.createFile(androidCsvContacts);
    }

    /**
     * Writing the data parsed from vCard file into the CSV file created above.
     */
    try(PrintWriter writer = new PrintWriter(Files.newBufferedWriter(androidCsvContacts, Charset.defaultCharset()),true)){
      writer.println("\"Last name\",\"General mobile\",\"General phone\",\"Home mobile\",\"Home phone\",\"Business mobile\",\"Business phone\",\"\"");
      for(MyCSVContact contact : csvContacts){

        System.out.println(contact);
        writer.println(contact);
      }
    }
  }
}

You will have to update the locations of the files according to the place where you have stored the vCard file (.vcf file) and where you want the CSV file (.csv file) to be created. I hope this article will be useful if you come across the same situation of exporting your data. If you have any questions, please write it in the comments section.

Comments

comments

About Mohamed Sanaulla

In his day job he works on developing enterprise applications using ADF. He is also the moderator of JavaRanch forums and an avid blogger.

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better