使用usb线传输大文件

参考资料:

  1. 使用USB数据线连接PC端和Android端进行数据的交互
  2. 安卓设备通过USB接口实现与pc端的简单数据通信
  3. Socket TCP/IP协议数据传输过程中的粘包和分包问题
  4. 【Android学习】socket长连接,数据粘包问题

  由于客户应用使用的场景比较特殊。明确要求不能使用网络进行数据交互,所以不得不研究了一下使用usb通信这方面。原理就是当连上usb线后,通过socket进行数据通信。只不过android设备作为socket服务端,pc作为socket的客户端。pc端在与服务端建立连接之前需要使用adb命令设置转发端口(具体可参考参考资料1和参考资料2)。
  端口这玩意随便填,不跟别人冲突就行。

adb shell am broadcast -a NotifyServiceStop
adb forward tcp:9999 tcp:9000
adb shell am broadcast -a NotifyServiceStart

##使用代码调用命令行
  如果想要完善android通过usb先进行数据交互,这里应该有不少的命令能用到,这里先记录一下调用命令的基本使用。

import java.io.BufferedReader
import java.io.InputStreamReaderfun main() {//读取连接设备val process = Runtime.getRuntime().exec("adb devices")val devices = BufferedReader(InputStreamReader(process.inputStream))val stringBuilder = StringBuilder()var line: String? = nullwhile (devices.readLine().apply { line = this } != null) {stringBuilder.append("$line\n")}println(stringBuilder.toString())//读取安装的应用val process2 = Runtime.getRuntime().exec("adb shell pm list packages")val packages = BufferedReader(InputStreamReader(process2.inputStream))val sb = StringBuilder()var line2: String? = nullwhile (packages.readLine().apply { line2 = this } != null) {sb.append("$line2\n")}println(sb.toString())}

  打印结果如下图所示:

  上面运行结果不错就是代码量有点多,用python简化一下就清晰不少。

import subprocessif __name__ == '__main__':# 读取连接设备subprocess.call("adb devices", shell=True)# 读取安装的应用subprocess.call("adb shell pm list packages", shell=True)

Android端

  Android端作为Socket的服务端,用来接收文件。为了防止分包的问题这里我定义了一个封包和解包方式。

  在文件传输的时候,数据的收发都会以这种结构去发送或者接收。(实际情况下肯定跟这个不一样,我这为了方便携带参数用的就是json格式的数据)。理论上就是每次读取的字节大小都在携带信息中。如果在循环读取中有一次没有读满,那就把它应当读取的字节都读取出来,再循环下一次数据读取,省着出现粘包的现象。(byte也别设太大,要不内存溢出)

package com.lyan.usbtestphoneimport android.annotation.SuppressLint
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Environment
import android.os.Handler
import com.blankj.utilcode.constant.PermissionConstants
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.LogUtils
import com.blankj.utilcode.util.PermissionUtils
import com.blankj.utilcode.util.ToastUtils
import kotlinx.android.synthetic.main.activity_main.*
import java.io.*
import java.net.ServerSocket
import java.net.Socketclass MainActivity : AppCompatActivity() {@SuppressLint("SetTextI18n")private val handler = Handler(Handler.Callback {when (it.what) {1 -> progressTv.text = "${it.obj}%"}false})override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)testBtn.setOnClickListener {startSocketServer { LogUtils.i("${Thread.currentThread().name} : $it") }}}private fun startSocketServer(callback: (name: Socket) -> Unit) = Thread {val file = File(Environment.getExternalStorageDirectory(), "copy.db3")if (file.exists()) {if (file.delete()) {file.createNewFile()}} else {file.createNewFile()}ServerSocket(9000).apply {logI("移动服务端等待客户端的连接...")val client = this.accept()callback.invoke(client)val bufferedOutputStream = BufferedOutputStream(DataOutputStream(FileOutputStream(file)))val bufferedInputStream = BufferedInputStream(DataInputStream(client.getInputStream()))val tagBytes = ByteArray(6)val infoBytes = ByteArray(4)var hTag: String//标记头var fTag: String//标记尾var infoSize: Int//携带数据的一些信息var jsonBytes: ByteArray//携带数据的byte数组var sendInfoData: SendInfoData//解析后的携带信息var readBytes: ByteArray//真正传输的数据的byte数组var readSize: Int//真正传输的数据的byte长度while (true) {val len = bufferedInputStream.read(tagBytes)if (len == -1) {break}hTag = String(tagBytes, 0, len)//标记头//读取进度信息infoSize = bufferedInputStream.read(infoBytes).run { bytesToInt(infoBytes) }jsonBytes = ByteArray(infoSize)sendInfoData = bufferedInputStream.read(jsonBytes).run {val infoJson = when (infoSize) {this -> {//读取数据完整LogUtils.i("读取数据完整")String(jsonBytes, 0, this)}else -> {//读取数据不完整(此处只要将分包处理后、粘包的问题自然就不会出现了)LogUtils.i("读取数据不完整")bufferedInputStream.read(jsonBytes, this, infoSize - this).run {String(jsonBytes, 0, infoSize)}}}LogUtils.i("其他信息 ------> $infoJson")GsonUtils.getGson().fromJson(infoJson, SendInfoData::class.java)}handler.obtainMessage(1, sendInfoData.percent).sendToTarget()//读取数据信息 传输数据大小 解析数据长度readBytes = ByteArray(sendInfoData.sendSize)readSize = bufferedInputStream.read(readBytes)//已读数据大小LogUtils.i("读流的长度:$readSize")if (readSize < sendInfoData.sendSize) {LogUtils.w("读取数据不完整!已读数据少于应读取数据的大小……","应读:${sendInfoData.sendSize}", "实读:$readSize")bufferedInputStream.read(readBytes, readSize, sendInfoData.sendSize - readSize)}fTag = bufferedInputStream.read(tagBytes).run { String(tagBytes, 0, this) }LogUtils.w("header:$hTag", "携带信息的字节数:$infoSize", "携带信息内容:$sendInfoData","每次应读取的数据字节数量:${sendInfoData.sendSize}", "footer:$fTag")bufferedOutputStream.write(readBytes)bufferedOutputStream.flush()}}}.start()//请求权限(文件读写权限)override fun onResume() {super.onResume()PermissionUtils.permission(PermissionConstants.STORAGE).callback(object : PermissionUtils.SimpleCallback {override fun onGranted() {ToastUtils.showShort("获取文件读写权限成功!")}override fun onDenied() {}}).request()}private fun bytesToInt(bytes: ByteArray): Int {return (0 until bytes.size).sumBy { (bytes[it].toInt() and 0xFF) shl it * 8 }}//每次接收数据的信息 进度 和 要保存的数据字节大小data class SendInfoData(val percent: String, val sendSize: Int)
}

pc端(正常应该是后台)

  在这种情况下后台就成客户端了。这里为了减少socket客户端的代码量,所以使用ptyhon来写:

import subprocess
import socket
import time
import copy
import json
import osclass SendInfoData(object):def __init__(self, percent="", sendSize=0):self.__percent = percentself.__sendSize = sendSizedef toJson(self):return json.dumps({"percent": self.__percent,"sendSize": self.__sendSize,})# int转byte数组
def intToBytes(intNumber=0): return intNumber.to_bytes(4, "little")# str转utf-8 byte数组
def strToUtf8Bytes(value): return bytes(value, encoding="utf-8")if __name__ == '__main__':subprocess.call("adb shell am broadcast -a NotifyServiceStop", shell=True)subprocess.call("adb forward tcp:9999 tcp:9000", shell=True)subprocess.call("adb shell am broadcast -a NotifyServiceStart", shell=True)client = socket.socket()result = client.connect(("127.0.0.1", 9999))# 文件路径filePath = "/Users/apple/Downloads/base.db3"# 文件大小allSize = os.path.getsize(filePath)fileSize = copy.deepcopy(allSize)print("%s\n" % fileSize)defaultReadSize = 1024 * 10progress = 0h = time.time()# 读取 文件with open(filePath, mode="rb") as readFile:while True:if fileSize <= 0: breakreadSize = defaultReadSize if fileSize > defaultReadSize else fileSizeprogress += readSizepercent = '{: .2f}'.format(progress * 1.0 / allSize * 100)print("进度:%s" % percent)# 读取内容readBytes = readFile.read(readSize)if not readBytes: breaktagH = strToUtf8Bytes("@tag:h")tagF = strToUtf8Bytes("@tag:f")# 携带信息infoJson = SendInfoData(percent, readSize).toJson()print("json:%s\n" % infoJson)infoBytes = strToUtf8Bytes(infoJson)infoSize = intToBytes(len(infoBytes))# 包裹传输数据client.send(tagH)  # 标记开头client.send(infoSize)  # 携带参数byte数据长度client.send(infoBytes)  # 携带参数内容client.send(readBytes)  # 真实传输的内容client.send(tagF)  # 标记结尾fileSize -= readSizeclient.close()f = time.time()print("用时:{: .0f}s".format((f - h)))

  这个例子的界面比较简单,就一个按钮和一个文本。手上测试的文件是一个900多兆的文件,在单位的时候试过一个4个多G的sqlite文件。而且文件在传输后一样可以正常使用。说明这个方式还是可行的。(当然在实际项目中这个例子仅仅是证明这个方式可行而已,具体优化部分肯定不带少的)

笔记:byte[]未写满,补全的方式

  目的是验证,这里以读取文件的内容为例,文件是txt格式的这里放了一段字符串“一二三四五六七八九十”。一共是10字符(一个字符2个字节,也就是20个字节)。定义一个byte数组长度为20。先读一半,然后再读剩下的一半。

import java.io.File
import java.io.FileInputStream
import java.nio.charset.Charsetfun main() {val path = "/Users/apple/Downloads/O.txt"val file = File(path)val inputStream = FileInputStream(file)//available()这个方法本质的意义是 剩余未被读取的字节数量println("文件的字节总数:${inputStream.available()}")val byte = ByteArray(20)val read1 = inputStream.read(byte, 0, 10)println(read1)println("read1后剩余字节数量:${inputStream.available()}")val read1Msg = String(byte, 0, read1, Charset.forName("GBk"))println(read1Msg)inputStream.read(byte, 10, 20 - read1)println("read2后剩余字节数量:${inputStream.available()}")val read2Msg = String(byte, 0, byte.size, Charset.forName("GBk"))println(read2Msg)}

  这块结合Android端那段代码看正好(一旦索引那想不明白,真不如运行代码来的实在),运行结果如下。

Android使用usb线传输大文件笔记相关推荐

  1. Android使用Socket(Tcp/Udp)协议进行数据传输(传输大文件)

    先揭晓一下前面天的抽奖活动中奖人员: 恭喜这位同学中奖,麻烦你在微信公众号留言你的收货地址,或者加入QQ群:417046685 来找我也行. 同时,知识星球的活动还在继续,现在加入知识星球立即赠送技术 ...

  2. JAVA实现服务器间拷贝文件,寻找在Java服务器之间传输大文件的好方法

    在这个项目中有一个主要的数据库服务器,其他安装在不同地方的服务器维护着自己的本地数据库.我们必须允许每个系统将其本地数据库更新为主要数据库上的任何版本.所有的服务器都运行Java环境.寻找在Java服 ...

  3. 局域网只看到少数电脑_利用局域网高速传输大文件的两种方法

    点击蓝字,关注我们 说到传输文件,我们可能很容易想到使用微信或者QQ发送文件,如果没有连接网络的话,可以考虑使用U盘或数据线,当然也可以使用第三方的共享文件,比如说茄子快传.以上方法的缺点自然是很明显 ...

  4. 如何快速在两台电脑之间传输大文件

    两台电脑如何传文件最快方法.我们在使用电脑的时候,有的情况下需要我们队两台电脑之间互相的传输大文件.那么我们应该通过什么样的方法传输最快速呢?我们一起来看看吧. 首先我们需要一根平时上网连接网络时用的 ...

  5. 为什么都说Dubbo不适合传输大文件?Dubbo支持的协议

    背景 之前公司有一个 Dubbo 服务,内部封装了腾讯云的对象存储服务 SDK,是为了统一管理这种三方服务的SDK,其他系统直接调用这个对象存储的 Dubbo 服务.用来避免因平台 SDK 出现不兼容 ...

  6. 快速传输大文件,怎么通过网络传大文件给对方(1G以上)

    在生活和工作中,我们总是要发送一些比较大的文件给别人,或者在自己的设备之间.在互联网日益发达的今天,我们可以用什么方法通过互联网快速传输大文件,发送1G以上的文件? 一.使用QQ传 在电脑上打开QQ, ...

  7. 浅析C#UDP传输大文件

    1.前言 众所周知,UDP通信是允许丢包的,这个通信方式本身就是"不太靠谱的",针对的是即便数据丢了几包也无所谓的情景,如果你非要用这个传输大文件(如一个视频),我只能说你和我一样 ...

  8. NodeJS使用socket传输大文件

    NodeJS的net模块为我们提供了socket相关API,介于此我们可以进行相关的网络编程.JavaScript 语言自身只有字符串数据类型,没有二进制数据类型,需要通过Buffer对象来处理.在这 ...

  9. 远程传输大文件使用什么平台好呢?

    远程传输大文件使用什么平台好呢?小文件倒是还可以通过QQ这样的方式进行传输,但是它对传输文件的大小有所限制,传输大文件就行不通了. 远程传输大文件使用什么平台好呢?传输大文件一个是要求传输稳定,不能说 ...

最新文章

  1. Pascal 错误代码及含义
  2. 零基础入门学习Python(20)-lambda表达式、filter()、map() BIF
  3. 网络推广外包之下“真我”徐起表示今年中国区定下进军2000万销量目标
  4. mysql innodb引擎--范围查询优化
  5. java线程太多卡顿_性能优化之卡顿延迟
  6. 本地修改远端 SAP UI5 框架文件的一个小技巧
  7. JMeter: org.apache.http.NoHttpResponseException
  8. NEERC 17 Problem I. Interactive Sort
  9. Editplus For Python[转]
  10. 项目wangkangluo1
  11. 如何利用图像识别、语音识别、文本挖掘做好鉴黄?
  12. SQL AZURE数据库创建,云计算体验之一
  13. 水下清淤机器人_国产第五代箱涵清淤机器人真机亮相上海城市管网展恒通环境展位...
  14. Android开发之实现图片自动滚动显示标签的ViewPager
  15. 基于websocket单台机器支持百万连接分布式聊天(IM)系统
  16. 人工智能系列:AI 可视化训练平台
  17. C语言 宾馆客房管理系统
  18. JS验证邮箱 身份证 VISA 卡[转]
  19. 交通信号灯课程设计_交通信号灯可以教设计师什么
  20. 数论及其应用——同余式定理

热门文章

  1. 【Matlab】求解微分方程{上}(通解和特解)
  2. PyCharm界面字体放大和缩小
  3. 计算机18个专业方向
  4. Voucher Key 相关SELinux
  5. Java计算文章多少字_java计算中文字数的代码实例
  6. 计算机上如何转换搜狗,无法切换到搜狗输入法怎么办
  7. domain-transfer reid郑哲东 joint 判别和生成REID
  8. SQL(之一)-SQL经典题目
  9. Python坦克大战小游戏(三):背景
  10. 本地项目的一个git仓库损坏如何恢复