amp@java

  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  99 随笔 :: 0 文章 :: 228 评论 :: 0 Trackbacks
 每次换手机,把旧手机的数据迁移到新手机就是个很麻烦的事情,幸好最近华为的“手机克隆”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 阅读(2138) 评论(0)  编辑  收藏 所属分类: Java commonAndroid

只有注册用户登录后才能发表评论。


网站导航: