amp@java

            BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
            99 隨筆 :: 0 文章 :: 228 評論 :: 0 Trackbacks
          <2017年11月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          常用鏈接

          留言簿(21)

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

           每次換手機,把舊手機的數據遷移到新手機就是個很麻煩的事情,幸好最近華為的“手機克隆”APP越來越強大,居然能夠把微信的聊天記錄包括圖片原封不動地遷移到新手機上,以前用微信自帶的聊天記錄轉移功能只能轉移文字信息,圖片視頻全部丟失,不知道現在的怎么樣。手機克隆還能把SD卡的內容也轉移過來,基本滿足了需要。
          但是要把手機上的東西傳到電腦就沒那么簡單了,現在已經沒有了以前的大容量存儲模式,只能選擇MTP模式,這種模式其實不是一個完整的文件系統,有很多限制,所以一些傳統的軟件讀取不到,例如FastCopy是用不了的,用Windows自帶的文件管理器來復制,開始計算時間就要等很久,中間出了個錯就前功盡棄;還有通過手機上的APP訪問電腦共享的方式,在手機上復制也可以,但是同樣會莫名其妙卡死,FTP同理,折騰了好久,還是覺得自己動手比較好。
          MTP協議在維基百科里解釋得比較清楚:https://en.wikipedia.org/wiki/Media_Transfer_Protocol ,簡單點說就是:
          1、不是以塊設備的形式訪問,跟U盤不同;
          2、只能單線程訪問,不能同時進行多個操作,只能一個接一個;
          3、控制權在設備上,對外展示的內容由設備決定;
          4、默認不能直接對文件進行部分修改,只能復制過來修改完再復制回去,但Android對協議做了擴展,能夠修改部分文件內容;
          5、在Linux上有些軟件能夠把它掛載為文件系統,這樣其他軟件就能像訪問普通文件系統一樣訪問了,但是Windows下似乎沒有。

          不過有人開發了一個在Windows下通過JNI實現的Java庫jmtp,項目托管在Google Code,被墻了,但是GitHub有人fork了一個,可以下載下來,我下載的是https://github.com/reindahl/jmtp
          里面包含了C++的代碼和Java的代碼,以及兩個已經編譯好的dll文件,分別用于Win32和Win64,把其中一個dll文件放在工程目錄下,再把Java源代碼加入工程中即可使用,文檔比較簡陋,但是看test目錄下的MtpTest.java,基本可以摸到如何使用了,這個協議比較簡單,其實沒什么功能,我要的只是把文件復制到電腦上。
          根據MtpTest.java,稍微修改一下,做個遞歸復制即可把手機上的所有文件復制到電腦上:
          package test;

          import java.io.File;
          import java.io.FileWriter;
          import java.io.IOException;
          import java.math.BigInteger;
          import java.nio.file.Files;
          import java.nio.file.Path;
          import java.nio.file.Paths;
          import java.rmi.server.SocketSecurityException;
          import java.util.ArrayList;


          import jmtp.PortableDevice;
          import jmtp.PortableDeviceFolderObject;
          import jmtp.PortableDeviceManager;
          import jmtp.PortableDeviceObject;
          import jmtp.PortableDeviceStorageObject;


          public class TestApp {

             

              
          public static void main(String[] args) {
                  
          // TODO Auto-generated method stub
                  
                  ArrayList
          <PortableDeviceStorageObject> devices = new ArrayList<>();

                  PortableDeviceManager manager 
          = new PortableDeviceManager();

                  
          for (PortableDevice device : manager) {
                      System.out.println(device);
                      device.open();
                      
                      
          // Iterate over deviceObjects
                      for (PortableDeviceObject object : device.getRootObjects()) {
                          String storageName
          =object.getName();
                          System.out.println(storageName);

                          
          // If the object is a storage object
                          if (object instanceof PortableDeviceStorageObject) {
                              PortableDeviceStorageObject storage 
          = (PortableDeviceStorageObject) object;
                              System.out.println(storage.getChildObjects().length);
                              
          for (PortableDeviceObject child : storage.getChildObjects()) {
                                      copyall(child,
          "E:\\手機備份\\"+object.getName());
                              }
                          }
                      }

                      device.close();
                      System.out.println(size);
                  }

            
            
              }
              
              
          public static void copyall(PortableDeviceObject obj,String path) {

                  if(obj instanceof PortableDeviceFolderObject) {
                    

                      String objName=obj.getName();
                      
          if(objName.contains(":")) {
                          objName
          =objName.replace(':''');
                      }
                      String newPath 
          = path+"\\"+objName;
                      System.out.println(
          "創建文件夾:"+newPath);
                      
                      File file = new File(newPath);
                      if(!file.exists()) {
                          file.mkdirs();
                      }
                      for(PortableDeviceObject subObj:((PortableDeviceFolderObject) obj).getChildObjects()) {             
                          copyall(subObj,newPath);
                      }
                  }
                  
          else {      
                      
          if(obj.getName().contains(":"))
                          
          return;
                      System.out.println(
          "開始復制文件到:"+path+"\\"+obj.getName());
                      File file 
          = new File(path);
                      obj.copy(file.toPath());                     
                      System.out.println(
          "文件復制完成!");
                  }
              }

          }
          其中發現有點問題:
          1、Android設備文件名里是可以包含冒號(:)的,但Windows是不可以的,所以復制到這些文件的時候會有問題,于是遇到目錄名這樣就把它改為中文的冒號(:),但是遇到文件名這樣就不行了,因為這個庫的copy函數只需要指定目標目錄,不需要指定目標文件名,所以這些文件只能放棄;
          2、Android手機的MTP協議是由“媒體存儲”這個系統APP控制的,有時候手機上可以看到的文件,通過MTP訪問卻怎么也看不到,重啟手機也不行,應該就是這個APP沒有更新數據,需要把它的系統數據清除掉,等它重建完重新訪問就可以看到了,不過這個重建時間非常長,可以查看它數據占用的空間,剛清除之后會發現它占用的空間會不斷增長,到了不增長的時候就是重建完了,就可以正常訪問了;
          3、這個庫有時候還有點bug,有一次發現它讀取到的文件和文件夾都沒有了最后一個.后面的部分,所以總是卡住,重新插拔一下手機數據線又沒問題了;
          4、為了避免復制了半天結果發現不完整,又要重來,最好在復制前先統計一下文件大小,看看跟手機上看到的占用存儲空間是不是一致,對于MTP設備上的文件,可以通過getSize函數得到大小,把上面復制操作改為大小累加即可,速度比復制快一些,不過由于小文件太多,也不會快很多。

          把手機里的文件復制到電腦后,通過一些簡單的分析,發現有很多其實是垃圾來的,也可以為手機空間清理提供參考,因為在電腦上分析起來比在手機上方便一些。例如一些視頻APP的緩存,居然超過1G,占用了寶貴的內部存儲空間,之前一直都沒發現,通過電腦里的按文件大小搜索才發現。
          posted on 2017-11-17 14:54 amp@java 閱讀(2267) 評論(0)  編輯  收藏 所屬分類: Java commonAndroid
          主站蜘蛛池模板: 延川县| 绥宁县| 高雄县| 荥阳市| 松溪县| 景宁| 郴州市| 河东区| 宜丰县| 禄丰县| 汽车| 濮阳县| 丹江口市| 喜德县| 新巴尔虎左旗| 麦盖提县| 九江市| 抚远县| 满洲里市| 如东县| 蛟河市| 扎鲁特旗| 龙井市| 定襄县| 蓬安县| 日喀则市| 大同市| 富顺县| 通江县| 偃师市| 正定县| 博白县| 正镶白旗| 石棉县| 盖州市| 涟源市| 裕民县| 松阳县| 胶南市| 绵阳市| 伽师县|