在stackoverflow上有个关于Android大文件上传的讨论。尝试着用Apache HttpComponents来解决。一番折腾,几多挫折,相当有趣。


环境准备

习惯了在Eclipse上开发,于是下载官方插件。早早升级到Eclipse4.3,当然是下载Google Update Site for Eclipse 4.3。这个插件包括GAE和GWT在内,需要挑选出Android的才好。

安装好的插件没有Android的SDK的,只有个SDK Manager,用这个再去下载及安装。在我折腾时4.3刚刚发布,但是没有Intel x86 Atom模拟器,只好4.2.2和4.3都装了。
个人的选择是这样的:

  • SDK Platform是必须的
  • Sample和Source也最好有,本地查资料快些。
  • 由于是在windwos上开发的,所以那个Intel x86 Atom虚拟机是需要的。(怕是只需要这个吧。

最后Extras里面的选择,Windows的话基本上必选那个Intel x86 Emulator Accelerator(HAXM),不然模拟器会慢到“飘起”。即使装上也没快不到哪里去,我那2010年的笔记本上虽然也能跑起来,但风扇也会不停的尖叫着...据我“耳测”,大抵接近《魔兽世界》或《星际争霸II》的水平。我了去的!

伴随着风扇的尖叫,折腾好那个简陋得不能再简陋的界面后,才发现我这个代码其实绝大部分无须Android的。(等我先去耳鸣一会儿...


主要思路

基本上是将大文件拆成小块,读取,上传。当所有文件块上传完成后,合并。

  1. 读取大文件。考虑到I/O竞争只用单线程;考虑到内存采取分批读取。

    ByteBuffer bb = ByteBuffer.allocate(partSize);
    int bytesRead = fc.read(bb);
    if (bytesRead == -1) {break;
    }
    byte[] bytes = bb.array();
    parts.put(new Part(createFileName(fileName, i), bytes));
    
  2. 将读取的文件块上传。通常多个线程会好些,但是太多又不行,默认用5线程上传。
    Part part = parts.take();
    if (part == Part.NULL) {parts.add(Part.NULL);// notify others to stop.break;
    } else {uploader.upload(part);
    }
    
  3. 读取和上传用BlockingQueue通信,最通用的生产/消费者模式。
  4. 服务器在接收到全部文件块后,合并。
  5. 还需考虑处理传送失败时,重新尝试上传部分。
  6. 由于Android的问题(参考下面Invocation Exception),在Android上使用时需要用jarjar这个工具先处理下。

JDK5追加的java.util.concurrent功能,一直都是“纸上谈兵”,从来没真正使用过。这次好好折腾了下...

 代码(优化中)上传到GitHub,如有兴趣或有需要请移步。


挫折坎坷

Invocation Exception

起手遇到这个问题,在Eclipse本地跑程序还没问题,装进Andorid模拟器后,启动就报错。查下来HttpComponents各种方法找不到。可明明jar包都扔进去的说。网上翻了好久,才搞清楚Android里面有个旧版本的HttpComponents在作怪!就让人有些火大的说!

您弄个老版本扔在那里,能不能想着升级下呢?听说还是beta版!

然后就是Class加载顺序,自然该是source,自带jar包,最后才是系统默认的优先顺序才对。这是多么基本的规矩啊?!

搜索时还看到好像是Android开发组(Dalvik team)的某位跑出来,推荐用HttpURLConnection代替HttpComponents。啥?!大哥你可以再搞笑些吗?虽然HttpComponents 4.x的评价不那么好,但你分别写个文件上传代码看看,差多少?差“老鼻子”了!

最后,既然不推荐,你把老版本去掉好吗?这才叫占茅坑...

 解决办法:用jarjar这个工具把最新版的HttpComponents都换下包名,程序中引用指向这个新包。下面是jarjar的rule,只替换org.apache.http,放过其他的比如org.apache.commons等。因为Android里面还藏了大票apache commons的东东!(在我花了九牛二虎之力,企图或是重新打包commons,或是提供‘伪’实现,一通折腾之后才发现!

 rule org.apache.http.** repack.org.apache.http.@1

Connection refused

解决掉包冲突后可以运行了。首当其冲的就是这个“拒绝连接”的错误。Android的AndroidManifest.xml里permission也加过了。

    <uses-permission android:name="android.permission.INTERNET" />

但还是失败。最终找到了问题所在——没把模拟器当成独立的环境,习惯上地址直接写http://localhost/xxx!模拟器里的localhost是模拟器自己,而不是宿主机器。又因为是在Windows上开发的,所以最方便就是IP地址——localhost改成192.168.x.x的局域网地址即可。

Request not MultipartHttpRequest

终于能和服务器通信了,但服务器端不停报错ClassCastException,说Request不是MultipartHttpServletRequest。

解决办法:这个是我自己的问题。临时找来的测试环境,Spring的multipartResolver就根本没配置。

  <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" p:defaultEncoding="utf-8" />

文件拷贝

这个就不细说了,说多了都是丢人!单单个from和to把自己绕晕了好久...

说结果吧。假如有两个FileChannel,分别是src和dest,需要将src的内容追加到dest的后面,该如何处理?有两种方法:

  1. dest.transferFrom(src, 其他参数);
  2. src.transferTo(其他参数, dest);

效果是一样的,细微的区别在于——作为参数的FileChannel的内部position会被改变!如果你对position有需求,那么就要当心了!(我在这里被绕晕的原因...应该是风扇还在一旁尖叫着...风扇应该怪模拟器...所以你看,最终都是google不好!灭哈哈!

Connection Timeout

这个要怪Apache了。4.2后多了释放连接的方法,如果不显式调用,就不释放连接。导致其他线程在拿连接时timeout。4.2之后的写法如下:

try {HttpResponse response = client.execute(post);// do something.
} catch (Exception e) {post.abort();throw new RuntimeException(e);
} finally {post.releaseConnection();
}

大叔的抱怨

多年前(2009)曾经摸过Android,当时只是觉得它的源代码比较粗糙。4年过去了,现在看来,还是...糙!

Java大文件上传(Android亦可)相关推荐

  1. JAVA大文件上传断点续传解决方案

    JAVA大文件上传断点续传解决方案 参考文章: (1)JAVA大文件上传断点续传解决方案 (2)https://www.cnblogs.com/songsu/p/11834425.html (3)ht ...

  2. java大文件上传解决方案

    最近遇见一个需要上传百兆大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现. 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表 ...

  3. java 大文件上传 断点续传(Socket、IO流)

    java两台服务器之间,大文件上传(续传),采用了Socket通信机制以及JavaIO流两个技术点,具体思路如下: 实现思路: 1.服:利用ServerSocket搭建服务器,开启相应端口,进行长连接 ...

  4. fastdfs redis java,大文件上传_断点续传_文件分片传输_fastdfs_前后端一站式解决方案...

    大文件上传,断点续传,秒传,fastdfs 项目介绍 实现h5与fastdfs之间的断点续传,大文件上传,秒传 软件架构 软件架构说明 webuploader+springboot+redis+fas ...

  5. java 大文件上传_JAVA大文件上传分片上传方法(附带demo)

    最近在做视频上传展示的相关业务!但是因为最开始使用的是单文件上传所以一旦遇到大文件上传的速度就非常慢!为此在网上一直找寻分片的方法!得到了思路! 直接讲一下我这边看了那么多文档加上自己理解写的demo ...

  6. java是怎么实现文件上传的_java怎么实现大文件上传

    Q1:javaWeb能和ftp实现大文件上传吗 java上传可以使用common-fileupload上传组件的.common-fileupload是jakarta项目组开发的一个功能很强大的上传文件 ...

  7. Java实现FTP批量大文件上传下载

    用Java实现FTP批量大文件上传下载 <iframe id="I0_1416224567509" style="margin: 0px; padding: 0px ...

  8. Java 使用 FTP 实现大文件上传下载

    Java 上传下载 1G 以上的文件可以通过 http 协议或 ftp 实现,但是 http 协议对文件上传大小有限制,而且还不稳定,因此这里使用 ftp 上传. ftp 上传方式有两种: 一.ASC ...

  9. java文件上传控件_java实现大文件上传控件

    这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了: 上传文件实体类: 看得 ...

最新文章

  1. webpack 最简打包结果分析
  2. HDU 4023 (博弈 贪心 模拟) Game
  3. 使用datatables 中文排序
  4. 详解Ibatis写CLOB数据
  5. C语言返回文件大小的功能(fseek和ftell的使用)
  6. python 编辑数学公式_用python编写数学公式
  7. SQL 全文索引 CONTAINS
  8. Zeppelin介绍
  9. 重新打包版Inno Setup 5.4.3
  10. I/O写入的原子性(Double Write)
  11. 在vue中使用axios发送post请求,参数方式
  12. spss和python stata matlab_毕业季:计量经济学实证研究中,哪款软件好(SPSS,Eviews,Matlab,stata,SAS)...
  13. DELPHI导出wps报错无效的类字符串
  14. 云栖号在线课堂—云服务器数据库快速入门特辑
  15. 关于汉王 唐人笔手写板 打开后间歇性手写程序闪退以及屏幕锁屏或者关闭后手写板自动usb拔出问题
  16. java题库管理考试管理源码,基于jsp的题库管理系统-JavaEE实现题库管理系统 - java项目源码...
  17. 移动终端基带芯片的基本架构介绍(三):移动终端基带芯片详细架构
  18. UEFI 模式下重新安装系统注意事项
  19. 利用栈实现中缀表达式转后缀表达式
  20. ValueError:Traceback(most ...)数据集中图片 not exists

热门文章

  1. GEE加载哨兵数据以及ESRI、EAS、FROM地表覆被产品
  2. 管理时间还是跟它赛跑?——与时间同行(7)
  3. 百度云新云虚拟主机3天试用配置discuz论坛
  4. 45. 跳跃游戏 II
  5. 用水云般自在的禅心,书写诗情画意的程序人生--悟透JavaScript
  6. JVM的私房笔记(一)类加载机制与类加载器 by 葵鱼
  7. js 正则是否包含某些字符串_js 正则包含字符
  8. 交换机端口橙色灯常亮是什么问题?
  9. 保皇胜负判定_保皇的规则是什么
  10. c4d如何用编程语言做动画,(图文+视频)C4D教程:那种山峦堆砌动画如何制作?...