Chinaunix首页 | 论坛 | 博客
  • 博客访问: 279761
  • 博文数量: 88
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 840
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-20 21:13
文章分类

全部博文(88)

文章存档

2022年(1)

2017年(1)

2016年(2)

2015年(1)

2014年(83)

分类: Java

2014-12-19 21:36:35

详解微软 Nokia Lumia手机导出的短信如何导入到安卓手机中


最近换手机了,但是有个很坑爹的问题,那就是微软这货太与众不同了。

我先前使用的是wp的lumia手机,使用“传输我的数据”应用导入到sd卡后,短信备份文件居然是一个vmsg文件,找遍全网,没有看到一个现成的解决转换问题的方法。由此可见微软有多孤僻。。。

不过,还好我是程序猿,,攻城师,所以这个问题没有难倒我哦,现在是彻底解决了。

下面我详细说一下从前到后的所有过程
1. 首先要使用“传输我的数据”应用导出至sd卡,在应用中单击屏幕最下面的“...”就可以看到。
2.然后将sd卡的vmsg备份文件拷贝到电脑上

3.攻城师来了。。。
看代码:
总共有三个源代码:
代码中有个文件路径的字串,随自己的实际情况更改!!

(1)

点击(此处)折叠或打开

  1. import java.io.File;
  2. import java.nio.ByteBuffer;
  3. import java.nio.CharBuffer;
  4. import java.nio.charset.Charset;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7. import java.util.Scanner;

  8. public class ConvertMain {

  9.     public static void main(String[] args) {
  10.         StringBuilder convertedString = new StringBuilder();
  11.         Map<String, Integer> map = new HashMap<String, Integer>();
  12.         int count = 1;
  13.         try {
  14.             Scanner scanner = new Scanner(new File("e:\\sms.vmsg"));
  15.             StringBuilder builder = new StringBuilder();
  16.             String str = new String();
  17.             Msg msg = new Msg();
  18.             do {
  19.                 str = scanner.nextLine();
  20.                 if (str.equals("BEGIN:VMSG")) {
  21.                     builder.append("sms,");
  22.                 } else if (str.startsWith("TEL")) {
  23.                     // 加入TEL
  24.                     msg.setTel(str.substring(4));
  25.                     if (!map.keySet().contains(str.substring(4))) {
  26.                         map.put(str.substring(4), count++);
  27.                     }

  28.                 } else if (str.startsWith("X-BOX")) {
  29.                     // 加入投送方式
  30.                     if (str.endsWith("INBOX")) {
  31.                         msg.setX_box(2);
  32.                     } else if (str.endsWith("SENDBOX")) {
  33.                         msg.setX_box(3);
  34.                     }
  35.                 } else if (str.startsWith("Date")) {
  36.                     // 加入日期
  37.                     msg.setDate(str.substring(5).replaceAll("/", "\\.")
  38.                             .substring(0, 16));
  39.                 } else if (str.startsWith("Subject")) {
  40.                     // 加入内容
  41.                     StringBuilder builder2 = new StringBuilder();
  42.                     builder2.append(str.substring(48));
  43.                     String str1 = scanner.nextLine();
  44.                     while (!str1.startsWith("END")) {
  45.                         builder2.append(str1);
  46.                         str1 = scanner.nextLine();
  47.                     }
  48.                     String source = builder2.toString().replaceAll("==", "=");
  49.                     byte[] array = getBytes(source.toCharArray());
  50.                     msg.setContent(QuotedPrintable.decode(array, "UTF-8")
  51.                             .replaceAll("\\s+", ""));
  52.                 }
  53.                 if (msg.getContent() != null && msg.getDate() != null
  54.                         && msg.getTel() != null && msg.getX_box() != 0) {
  55.                     if (msg.getX_box() == 2) {
  56.                         // deliver + ",count"
  57.                         builder.append("deliver,    " + msg.getTel() + ",,,"
  58.                                 + msg.getDate() + "," + map.get(msg.getTel())
  59.                                 + "," + msg.getContent() + "\r");
  60.                     } else if ((msg.getX_box() == 3)) {
  61.                         // send
  62.                         builder.append("submit,,    " + msg.getTel() + ",,"
  63.                                 + msg.getDate() + "," + map.get(msg.getTel())
  64.                                 + "," + msg.getContent() + "\r");
  65.                     }
  66.                     convertedString.append(builder.toString());
  67.                     msg = new Msg();
  68.                     builder = new StringBuilder();
  69.                 }
  70.             } while (str != "" && str != null);

  71.         } catch (Exception e) {
  72.         }
  73.         System.out.println(convertedString);
  74.     }

  75.     private static byte[] getBytes(char[] chars) {
  76.         Charset cs = Charset.forName("UTF-8");
  77.         CharBuffer cb = CharBuffer.allocate(chars.length);
  78.         cb.put(chars);
  79.         cb.flip();
  80.         ByteBuffer bb = cs.encode(cb);

  81.         return bb.array();

  82.     }
  83. /*
  84.     // byte转char
  85.     private static char[] getChars(byte[] bytes) {
  86.         Charset cs = Charset.forName("UTF-8");
  87.         ByteBuffer bb = ByteBuffer.allocate(bytes.length);
  88.         bb.put(bytes);
  89.         bb.flip();
  90.         CharBuffer cb = cs.decode(bb);

  91.         return cb.array();
  92.     }*/
  93. }
(2)

点击(此处)折叠或打开

  1. import java.io.UnsupportedEncodingException;


  2. public class QuotedPrintable {

  3.     private final static byte TAB = 0x09; // /t
  4.     private final static byte LF = 0x0A; // /n
  5.     private final static byte CR = 0x0D; // /r
  6.     //private final static byte SPACE = 0x20; // ' '
  7.     private final static byte EQUALS = 0x3D; // '='
  8.       
  9.     private final static byte LIT_START = 0x21;
  10.     private final static byte LIT_END = 0x7e;
  11.       
  12.     private final static int MAX_LINE_LENGTH = 76;
  13.       
  14.     private static int mCurrentLineLength = 0;
  15.   
  16.     /**
  17.      * A method to decode quoted printable encoded data.
  18.      * It overrides the same input byte array to save memory. Can be done
  19.      * because the result is surely smaller than the input.
  20.      *
  21.      * @param qp
  22.      * a byte array to decode.
  23.      * @return the length of the decoded array.
  24.      */
  25.     public static int decode(byte [] qp) {
  26.         int qplen = qp.length;
  27.         int retlen = 0;
  28.   
  29.         for (int i=0; i < qplen; i++) {
  30.             // Handle encoded chars
  31.             if (qp[i] == '=') {
  32.                 if (qplen - i > 2) {
  33.                     // The sequence can be complete, check it
  34.                     if (qp[i+1] == CR && qp[i+2] == LF) {
  35.                         // soft line break, ignore it
  36.                         i += 2;
  37.                         continue;
  38.   
  39.                     } else if (isHexDigit(qp[i+1]) && isHexDigit(qp[i+2]) ) {
  40.                         // convert the number into an integer, taking
  41.                         // the ascii digits stored in the array.
  42.                         qp[retlen++]=(byte)(getHexValue(qp[i+1])*16
  43.                                        + getHexValue(qp[i+2]));
  44.   
  45.                         i += 2;
  46.                         continue;
  47.   
  48.                     } else {
  49.                         System.out.println("decode: Invalid sequence = " + qp[i+1] + qp[i+2]);
  50.                     }
  51.                 }
  52.                 // In all wrong cases leave the original bytes
  53.                 // (see RFC 2045). They can be incomplete sequence,
  54.                 // or a '=' followed by non hex digit.
  55.             }
  56.   
  57.             // RFC 2045 says to exclude control characters mistakenly
  58.             // present (unencoded) in the encoded stream.
  59.             // As an exception, we keep unencoded tabs (0x09)
  60.             if( (qp[i] >= 0x20 && qp[i] <= 0x7f) ||
  61.                  qp[i] == TAB || qp[i] == CR || qp[i] == LF) {
  62.                 qp[retlen++] = qp[i];
  63.             }
  64.         }
  65.   
  66.         return retlen;
  67.     }
  68.   
  69.     private static boolean isHexDigit(byte b) {
  70.         return ( (b>=0x30 && b<=0x39) || (b>=0x41&&b<=0x46) );
  71.     }
  72.   
  73.     private static byte getHexValue(byte b) {
  74.         return (byte)Character.digit((char)b, 16);
  75.     }
  76.   
  77.     /**
  78.      *
  79.      * @param qp Byte array to decode
  80.      * @param enc The character encoding of the returned string
  81.      * @return The decoded string.
  82.      */
  83.     public static String decode(byte[] qp, String enc) {
  84.         int len=decode(qp);
  85.         try {
  86.             return new String(qp, 0, len, enc);
  87.         } catch (UnsupportedEncodingException e) {
  88.             return new String(qp, 0, len);
  89.         }
  90.     }
  91.   
  92.     /**
  93.      * A method to encode data in quoted printable
  94.      *
  95.      * @param content
  96.      * The string to be encoded
  97.      * @param enc
  98.      * The character encoding of the content string
  99.      * @return The encoded string. If the content is null, return null.
  100.      */
  101.     public static String encode(String content, String enc) {
  102.         if (content == null)
  103.             return null;
  104.           
  105.         byte[] str = null;
  106.         try {
  107.             str = content.getBytes(enc);
  108.         } catch (UnsupportedEncodingException e) {
  109.             str = content.getBytes();
  110.         }
  111.         return encode(str);
  112.     }
  113.     /**
  114.      * A method to encode data in quoted printable
  115.      *
  116.      * @param content
  117.      * The byte array of the string to be encoded
  118.      * @return The encoded string. If the content is null, return null.
  119.      */
  120.     public static String encode(byte[] content) {
  121.         if (content == null)
  122.             return null;
  123.           
  124.         StringBuilder out = new StringBuilder();
  125.           
  126.         mCurrentLineLength = 0;
  127.         int requiredLength = 0;
  128.           
  129.         for (int index = 0; index < content.length; index++) {
  130.             byte c = content[index];
  131.               
  132.             if (c >= LIT_START && c <= LIT_END && c != EQUALS) {
  133.                 requiredLength = 1;
  134.                 checkLineLength(requiredLength, out);
  135.                 out.append((char)c);
  136.             } else {
  137.                 requiredLength = 3;
  138.                 checkLineLength(requiredLength, out);
  139.                 out.append('=');
  140.                 out.append(String.format("%02X", c));
  141.             }
  142.         }
  143.         return out.toString();
  144.     }
  145.       
  146.     private static void checkLineLength(int required, StringBuilder out) {
  147.         if (required + mCurrentLineLength > MAX_LINE_LENGTH - 1) {
  148.             out.append("=/r/n");
  149.             mCurrentLineLength = required;
  150.         } else
  151.             mCurrentLineLength += required;
  152.     }

  153. }
(3)

点击(此处)折叠或打开

  1. public class Msg {
  2.     
  3.     private String tel;
  4.     private int x_box;
  5.     private String date;
  6.     private String content;
  7.     
  8.     public String getTel() {
  9.         return tel;
  10.     }
  11.     public void setTel(String tel) {
  12.         this.tel = tel;
  13.     }
  14.     public int getX_box() {
  15.         return x_box;
  16.     }
  17.     public void setX_box(int x_box) {
  18.         this.x_box = x_box;
  19.     }
  20.     public String getDate() {
  21.         return date;
  22.     }
  23.     public void setDate(String date) {
  24.         this.date = date;
  25.     }
  26.     public String getContent() {
  27.         return content;
  28.     }
  29.     public void setContent(String content) {
  30.         this.content = content;
  31.     }
  32. }

4. 运行后,就可以在控制台中看到解析好的内容。在控制台中,全选,然后复制。
5.在桌面上新建一个1.csv文件,注意是csv文件,用“记事本”打开,然后把复制的内容拷贝进去。然后把所有以“Invalid。。。”开头的行(就在文件开头)全部去掉。然后点击另存为。。。在下面的编码上选择“UTF-8”,必须如此做!
6.开始导入
(1)在电脑上安装豌豆荚
(2)找一个已经root的手机,如果你的手机没有root,那么赶紧找一个已经root了的(往手机里写短信需要root权限)
(3)使用豌豆荚连接安卓手机,然后打开安卓手机,在授权管理中,将豌豆荚的所有软件全部标记为“信任”,“不拦截”之类的权限!!!这个很重要
(4)在电脑豌豆荚左边菜单里选择“备份和恢复”,然后选择从文件恢复,选择刚刚做好的那个csv文件,然后点击导入。这时豌豆荚就开始往手机里写文件了!!
(5)如果你的手机不是root的,你是借用别的已经root的手机,比如笔者的mx3这样的。看第6步

(6)在刚导好短信的手机上下载qq同步助手,安装,然后登录qq号,然后在“菜单”=》“账号与设置”=》“sd卡导入导出”中,选择导出。
(7)在要转移过去的手机(没有root的,比如笔者的mx3上安装qq同步助手
(7)在文件管理器中找到QQPim文件夹,把这个文件夹下的backup拷贝到你想要转移过去的手机。注意要完全相同的目录
(8)打开你自己最终要转移的手机的qq同步助手,依然找到sd卡导入导出,这时,选择“导入”!!!!


至此,彻底完成了VMSG文件的导入,将这些短信转移到了任意平台的手机!!!





阅读(7504) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~