最近因为项目需要,研究了一下C#调用adb传输和推送数据到安卓设备上。 查了资料发现安卓设备与电脑连接,传输数据有两种方式: 1.通过adb
2.socket。 市面上安卓设备管理工具如:豌豆荚、XX手机助手大多采用socket方式,监听某个端口,通过socket传输数据。socket优点是速度快,不会被语言和编码限制,缺点是开发量大,难懂(至少对于大多数开发者是这样的)。

下面介绍一下adb使用的一些经验和技巧,文章最后附有我写的一个程序。


1.ADB简介及命令

ADB:Android Debug Bridge,安卓调试桥接工具。(连接设备时要保证pc上安装有该设备的驱动)
传输数据文件常用的命令有:

  • adb shell 进入shell界面
  • pull拷贝文件到电脑: pull sdcard/a.jpg d:\a.jpg
  • push拷贝文件到设备:push d:\a.jpg sdcard/a.jpg
  • mkdir创建文件夹:mkdir xxx mkdir –p xxx/xxx(递归创建文件夹)
  • ls 列出当前文件夹下所有文件和文件夹 *
  • cd转到指定文件夹下


    进入shell

    转到目录,列出目录中的文件和文件夹


    pull、push命令不必进入shell


    创建文件夹

*由于cmd字符集的问题,汉字命名的文件在ls时出现乱码,原因是cmd采用gbk,Android系统采用的UTF-8所致,可以更改字符集和展示字体,见此。Ps:在程序中推荐大家使用英文和数字来命名文件和文件夹,免得出现不必要的辛苦,因为通过修改命名方式和修改Android底层adb的源码再次编译相比,真是不要太简单!

2.C#程序

首先说明一下我的开发环境:VS2010 .Net Framework 4.0

文件结构

  1. 在程序中最好集成adb.exe,使用起来也很方便
  2. 使用log4net记录数据传输时的返回信息
  3. ProcessHelper类用来监控cmd进程中输入输出流等
    贴一下ProcessHelper类的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Threading;namespace AndroidDataTransform
{public class ProcessHelper{private static Process GetProcess(){var mProcess = new Process();mProcess.StartInfo.CreateNoWindow = true;mProcess.StartInfo.UseShellExecute = false;mProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;mProcess.StartInfo.RedirectStandardInput = true;mProcess.StartInfo.RedirectStandardError = true;mProcess.StartInfo.RedirectStandardOutput = true;mProcess.StartInfo.StandardOutputEncoding = Encoding.UTF8;return mProcess;}private static string ReadStandardOutputLine(Process p){var tmp = new StringBuilder();//当下一次读取时,Peek可能为-1,但此时缓冲区其实是有数据的。正常的Read一次之后,Peek就又有效了。if (p.StandardOutput.Peek() == -1)tmp.Append((char)p.StandardOutput.Read());while (p.StandardOutput.Peek() > -1){tmp.Append((char)p.StandardOutput.Read());}return tmp.ToString();}/// <summary>/// 读取数据的时候等待时间,等待时间过短时,可能导致读取不出正确的数据。/// </summary>public static int WaitTime = 50;/// <summary>/// 连续运行模式,支持打开某程序后,持续向其输入命令,直到结束。/// </summary>/// <param name="exePath"></param>/// <param name="args"></param>/// <param name="moreArgs"></param>/// <returns></returns>public static RunResult RunAsContinueMode(string exePath, string args, string[] moreArgs){var result = new RunResult();try{using (var p = GetProcess()){p.StartInfo.FileName = exePath;p.StartInfo.Arguments = args;p.Start();//先输出一个换行,以便将程序的第一行输出显示出来。//如adb.exe,假如不调用此函数的话,第一行等待的shell@android:/ $必须等待下一个命令输入才会显示。p.StandardInput.WriteLine();result.OutputString = ReadStandardOutputLine(p);result.MoreOutputString = new Dictionary<int, string>();for (int i = 0; i < moreArgs.Length; i++){p.StandardInput.WriteLine(moreArgs[i] + '\r');//必须等待一定时间,让程序运行一会儿,马上读取会读出空的值。Thread.Sleep(WaitTime);result.MoreOutputString.Add(i, ReadStandardOutputLine(p));}// Do not wait for the child process to exit before// reading to the end of its redirected stream.// p.WaitForExit();// Read the output stream first and then wait.p.WaitForExit();result.ExitCode = p.ExitCode;result.Success = true;}}catch (Win32Exception ex){result.Success = false;//System Error Codes (Windows)//http://msdn.microsoft.com/en-us/library/ms681382(v=vs.85).aspxresult.OutputString = string.Format("{0},{1}", ex.NativeErrorCode, SystemErrorCodes.ToString(ex.NativeErrorCode));}catch (Exception ex){result.Success = false;result.OutputString = ex.ToString();}return result;}public static RunResult Run(string exePath, string args){var result = new RunResult();try{using (var p = GetProcess()){p.StartInfo.FileName = exePath;p.StartInfo.Arguments = args;p.Start();//获取正常信息if (p.StandardOutput.Peek() > -1)result.OutputString = p.StandardOutput.ReadToEnd();//获取错误信息if (p.StandardError.Peek() > -1)result.OutputString = p.StandardError.ReadToEnd();// Do not wait for the child process to exit before// reading to the end of its redirected stream.// p.WaitForExit();// Read the output stream first and then wait.p.WaitForExit();result.ExitCode = p.ExitCode;result.Success = true;}}catch (Win32Exception ex){result.Success = false;//System Error Codes (Windows)//http://msdn.microsoft.com/en-us/library/ms681382(v=vs.85).aspxresult.OutputString = string.Format("{0},{1}", ex.NativeErrorCode, SystemErrorCodes.ToString(ex.NativeErrorCode));}catch (Exception ex){result.Success = false;result.OutputString = ex.ToString();}return result;}public class RunResult{/// <summary>/// 当执行不成功时,OutputString会输出错误信息。/// </summary>public bool Success;public int ExitCode;public string OutputString;/// <summary>/// 调用RunAsContinueMode时,使用额外参数的顺序作为索引。/// 如:调用ProcessHelper.RunAsContinueMode(AdbExePath, "shell", new[] { "su", "ls /data/data", "exit", "exit" });/// 果:MoreOutputString[0] = su执行后的结果字符串;MoreOutputString[1] = ls ...执行后的结果字符串;MoreOutputString[2] = exit执行后的结果字符串/// </summary>public Dictionary<int, string> MoreOutputString;public new string ToString(){var str = new StringBuilder();str.AppendFormat("Success:{0}\nExitCode:{1}\nOutputString:{2}\nMoreOutputString:\n", Success, ExitCode, OutputString);if (MoreOutputString != null)foreach (var v in MoreOutputString)str.AppendFormat("{0}:{1}\n", v.Key, v.Value.Replace("\r", "\\Ⓡ").Replace("\n", "\\Ⓝ"));return str.ToString();}}}
}

AdbHelper类中包括了连接设备、列出指定文件夹、文件的传输

  • 将文件拷贝至设备
    若result信息中包含No such file or directory 证明设备上没有该路径。为了保留pc上文件的路径,需要在设备上创建相应的文件夹。
    例如:通过输出字符串:" failed to copy 'F:\padData\image\1.jpg' to 'sdcard/21at/output/image/1.jpg': No such file or directory"
    我们要获得目标文件夹是sdcard/21at/output/image/,具体实现见下:
        /// <summary>/// 将文件拷贝到设备上(不适用于文件夹)/// </summary>/// <param name="deviceNo"></param>/// <param name="pcPath"></param>/// <param name="devPath"></param>/// <returns></returns>public static bool CopyToDevice(string deviceNo, string pcPath, string devPath){//adb push [-p] <local> <remote> //- copy file/dir to devicevar result = ProcessHelper.Run(AdbExePath, string.Format("-s {0} push {1} {2}", deviceNo, pcPath, devPath));m_log.Info("推送PAD时结果:" + result.ToString());if (result.ExitCode != 0|| (result.OutputString.Contains("failed")&& result.OutputString.Contains("No such file or directory")))//若出现设备文件夹不存在的情况,则创建该文件夹{//构建拷贝后设备路径int index1 = result.OutputString.IndexOf("failed to copy ");//输出字符串:" failed to copy 'F:\padData\image\1.jpg' to 'sdcard/21at/output/image/1.jpg': No such file or directory"string temp = result.OutputString.Substring(index1);int index2 = temp.IndexOf(devPath);int index3 = temp.IndexOf("': No such file or directory");string devPath2 = temp.Substring(index2, index3 - index2);//设备图片路径devPath2 = devPath2.Substring(0, devPath2.LastIndexOf('/'));var moreArgs = new[] { "su", "mkdir -p "+ devPath2, "exit", "exit" };//shell 方式创建文件夹result = ProcessHelper.RunAsContinueMode(AdbExePath, string.Format("-s {0} shell", deviceNo), moreArgs);m_log.Info("创建文件夹:" + devPath2);m_log.Info("创建文件夹结果:" + result.ToString());//再次推送该文件result = ProcessHelper.Run(AdbExePath, string.Format("-s {0} push {1} {2}", deviceNo, pcPath, devPath));m_log.Info("再次推送PAD结果:" + result.ToString());}if (!result.Success|| result.ExitCode != 0|| (result.OutputString != null && result.OutputString.Contains("failed"))){return false;throw new Exception("push 执行返回的结果异常:" + result.OutputString);}return true;}
  • 将文件拷贝至PC
/// <summary>/// 拷贝文件到PC上/// </summary>/// <param name="deviceNo"></param>/// <param name="devPath"></param>/// <param name="pcPath"></param>/// <returns></returns>public static bool CopyFromDevice(string deviceNo, string devPath, string pcPath){//使用Pull命令将数据库拷贝到Pc上//adb pull [-p] [-a] <remote> [<local>]var result = ProcessHelper.Run(AdbExePath, string.Format("-s {0} pull {1} {2}", deviceNo, devPath, pcPath));m_log.Info("推送PC时结果:" + result.ToString());if (!result.Success|| result.ExitCode != 0|| (result.OutputString != null && result.OutputString.Contains("failed"))){return false;throw new Exception("pull 执行返回的结果异常:" + result.OutputString);}return true;} 
  • 列出指定目录
         /// <summary>/// 获取指定的目录/// </summary>/// <param name="deviceNo"></param>/// <param name="path"></param>/// <returns></returns>public static List<string>  ListDataFolder(string deviceNo, string path){var moreArgs = new[] { "su", "ls " + path, "exit", "exit" };var result = ProcessHelper.RunAsContinueMode(AdbExePath, string.Format("-s {0} shell", deviceNo), moreArgs);m_log.Info("获取路径结果:" + result.ToString());var itemsString = result.MoreOutputString[1];var items = itemsString.Split(new[] { "$", "#", "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries);var itemsList = new List<String>();foreach (var item in items){var tmp = item.Trim();//移除第一行,输入的命令if (tmp.Contains(moreArgs[1]))continue;//若有Permission denied证明没有该路径,直接退出if (tmp.Contains(path + ": Permission denied"))break;//移除空白行if (string.IsNullOrEmpty(tmp))continue;//移除最后两行的root@androidif (tmp.ToLower().Contains("root@") || tmp.ToLower().Contains("shell@"))continue;if (tmp.Equals("su") || tmp.Contains("su: not found"))//移除sucontinue;itemsList.Add(path + "/" + tmp);}itemsList.Sort();return itemsList;}

文件app.config中记录了指定的下载的文件夹,以及当前程序标示是上传还是下载

<appSettings><!--文件路径:实际路径是 sdcard/Tencent或extSdCard/Tencent--><add key="PadDataPath" value="/Tencent"/><!--程序是上传(1)还是下载(0)--><add key="type" value="0"/></appSettings>

在C#的程序中可通过
System.Configuration.ConfigurationManager.AppSettings["PadDataPath"]方式来获取设置的value值。

程序运行图

我写的程序在此。

C#通过adb传输安卓设备数据相关推荐

  1. 通过网络adb连接安卓设备传输文件

    相关文章 1.Android ADB命令大全----https://blog.csdn.net/YanLai20/article/details/48047813?utm_medium=distrib ...

  2. 安卓设备数据转移到ios设备

    某度上有问题,用不了,在某贴上看到解决办法,整理了一下. 1.首先在安卓设备上在https://support.apple.com/zh-cn/HT205042下载"转移到 iOS" ...

  3. adb查看安卓设备系统Android版本

    adb shell getprop "ro.build.version" 结果中如下两项便是版本信息: [ro.build.version.release]: [4.4.4] [r ...

  4. android 通过adb工具实现无线连接安卓设备并调试

    最常用电脑连接安卓设备是通过USB数据线,不多赘述,下面是通过adb工具实现局域网无线连接安卓设备,可以用于AS调试. windows电脑是在amd中输入adb命令,和mac电脑有所差异: 以mac电 ...

  5. 转移到ios下载安卓_Move to iOS-转移到iOS(数据转移)app下载2.10.0 安卓官方版-将安卓设备的通讯录,照片,app购买记录等无差别转移到ios设备的软件西西软件下载...

    转移到iOS(数据转移)app,安卓用户无需担心更换iphone后自己的电话,通讯录,照片,应用程序购买记录等都丢失的状况了,这款转移到iOS(数据转移)app可以帮你把这些数据都转移到ios设备上, ...

  6. 怎么从安卓设备转移数据到苹果_如何将数据从安卓设备转移到iPhone12

    如果之前是安卓用户,在购买 iphone 12 新款手机之后,如何从安卓转移数据到 ios?可以通过苹果官方提供的"转移到 ios"应用,将安卓手机中的内容进行转移,感兴趣的朋友快 ...

  7. 苹果新旧手机数据转移_如何将数据从安卓设备转移到iPhone12_苹果手机_手机学院...

    如果之前是安卓用户,在购买 iPhone 12 新款手机之后,如何从安卓转移数据到 iOS?可以通过苹果官方提供的"转移到 iOS"应用,将安卓手机中的内容进行转移,一起来了解一下 ...

  8. php模拟安卓端捉取数据,ios - PHP如何模拟安卓设备,请求API接口的数据

    抓包获取的安卓设备请求API时候携带了这么一大堆数据,PHP如何模拟这些数据? customerId: 801 clientAgent: M351#1080*1800 versionId: 5.6.2 ...

  9. 如何通adb命令删除安卓设备上指定的文件和apk

    一.删除文件 1.通过adb命令连接安卓设备 adb connect ip 2.adb root tools>adb remount tools>adb shell #su #cd sys ...

最新文章

  1. Linux静默安装oracle
  2. 低功耗/远距离lora模块:物联网智能家居、抄表多领域应用SX1262芯片方案
  3. 8.霍夫变换:线条——动手编码、霍夫演示_4
  4. Splash resource_timeout 属性
  5. Redmi王腾:Redmi 10X还会带来全新滤镜
  6. c语言标识符的规范,初识C语言-声明和使用变量、标识符的命名规范以及基本数据类型...
  7. python webserver模块,python探索之BaseHTTPServer-实现Web服务器介绍
  8. [转载] Java为什么不允许覆盖静态方法?
  9. 你的第一个 iOS 应用程序: 100% 的编程方式
  10. 基于SSM高校教师教务信息管理系统
  11. php解析dcm,DICOM入门(三)——解析DCM文件
  12. java wav 转 mp3_使用jave2将音频wav转换成mp3格式
  13. 二维向量叉积的几何意义
  14. 从0到1,搭建经营分析体系
  15. 远程启动IDEA时报错Startup Error: Unable to detect graphics environment
  16. 深度分享:解读中国老年行业创新创业生态,六位创业者带来老年创投/社交电商/教育/旅游/化妆品一线实战经验心得!
  17. matlab绘制图形hold on_MATLAB中hold on和figure的区别?画三维图为什么一定要meshgrid?...
  18. 对于低收入的研究生来说,是否说明读研的意义并不大
  19. hdu find a way to escape(1593)
  20. pytorch模型容器Containers nn.ModuleDict、nn.moduleList、nn.Sequential

热门文章

  1. lumbar spine的意思_lumbar spine
  2. 【科技知识】量子计算机可以破译全世界的密码?
  3. turtle空间坐标系
  4. LINUX设置临时路径
  5. 起点在线时长经验值自动领取插件
  6. 02-Vue-cli 环境搭建
  7. [附源码]计算机毕业设计财务管理系统Springboot程序
  8. html footer写法,HTML5 footer标签元素 css3布局教程
  9. SQL_实验1.5 清华大学出版社
  10. python数据挖掘系列(一)