`
clxy
  • 浏览: 80020 次
社区版块
存档分类
最新评论

Java大文件上传(Android亦可)

 
阅读更多

  在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年过去了,现在看来,还是...糙!

  • 大小: 37.9 KB
  • 大小: 61.3 KB
  • 大小: 40.2 KB
  • 大小: 26.4 KB
2
1
分享到:
评论
2 楼 tanmingjuntan 2015-11-05  
客户端代码写得还是很好的,还劳烦发一下服务端代码到我的邮箱。谢谢!934914780@qq.com
1 楼 tanmingjuntan 2015-11-05  
你这分块服务侧代码有吗

相关推荐

    java大文件分块上传断点续传demo

    在Java开发中,大文件上传是一项常见的需求,尤其是在云存储、文件分享等场景下。由于网络环境的不稳定性,单纯的一次性上传大文件可能会因为网络中断而导致上传失败,这时就需要断点续传功能来保证文件传输的可靠性...

    java Swing 上传文件

    java Swing 上传文件-------------------------------------------------------------------------------------------------------------------------------------------------------

    android文件上传控件

    在Android应用开发中,文件上传是一项常见的功能,尤其在社交、云存储或协作类应用中。本篇将详细讲解如何在Android中实现文件上传,并结合“亲测可用”的控件来探讨具体实践。 首先,我们需要了解Android中的文件...

    java android 读取dat文件

    在Java和Android开发中,有时会遇到需要处理各种类型的文件,包括`.dat`文件。`.dat`文件本身没有特定的格式,它通常被用来存储任意数据,由创建它的应用程序定义结构。本篇将深入探讨如何在Java和Android环境中读取...

    LuaJava在Android平台的动态链接库文件

    标题 "LuaJava在Android平台的动态链接库文件" 指出的是将Lua与Java集成在Android应用开发中的技术实践。Lua是一种轻量级的脚本语言,常用于游戏开发和系统配置等场景,而Java是Android应用的主要编程语言。在...

    java上传大文件带进度条

    可自主限制上传文件的文件类型 showProgress &quot;&quot; &quot;&quot; &quot;&quot; 方法的第二个参数为限制上传文件类型 多文件时用 ‘|’ 进行分割 如: zip| rar| jif

    java Android乒乓球

    java Android乒乓球java Android乒乓球java Android乒乓球java Android乒乓球java Android乒乓球java Android乒乓球java Android乒乓球java Android乒乓球java Android乒乓球java Android乒乓球java Android乒乓球...

    qt调用JAVA文件示例

    本文将详细讲解如何在QT项目中调用JAVA文件,以实现与Android原生系统的交互。 首先,我们需要了解QT的QAndroidJniObject类,它是QT为与Android Java层交互提供的一种工具。QAndroidJniObject允许我们在C++代码中...

    java带进度条大文件上传

    在Java开发中,大文件上传是一项常见的需求,尤其是在文件共享、云存储等场景。"java带进度条大文件上传"的实现主要涉及到以下几个关键知识点: 1. **虚拟内存技术**:传统的文件上传方式可能会遇到内存限制,特别...

    android 选择文件上传至服务器 包含服务器代码

    - 使用断点续传或分块上传,以应对大文件上传。 - 使用多线程上传提高效率,但需注意并发控制以避免服务器过载。 通过以上步骤,可以实现Android客户端的文件选择和上传功能,并在服务器端成功接收并保存这些文件...

    java实现文件上传到服务器

    而文件系统存储则更灵活,适合大文件,但数据恢复可能复杂。 总结,Java Web实现文件上传到服务器,主要涉及Servlet处理HTTP请求,读写文件,以及可能的数据库操作。在Oracle数据库中存储文件时,需使用JDBC和BLOB...

    课程设计大作业基于java的Android Studio实现井字棋小游戏源码.zip

    课程设计大作业基于java的Android Studio实现井字棋小游戏源码课程设计大作业基于java的Android Studio实现井字棋小游戏源码课程设计大作业基于java的Android Studio实现井字棋小游戏源码课程设计大作业基于java的...

    android+javaCV环境配置

    在Android平台上进行计算机视觉开发时,JavaCV是一个非常重要的库,它为开发者提供了与OpenCV、FFmpeg等库的交互接口。JavaCV使得在Android应用中实现图像处理、视频分析等功能变得更为简单。本文将详细介绍如何配置...

    java Socket文件断点续传 Android

    本项目通过Java Socket实现了这一功能,特别适用于大文件的上传,提高了用户体验。 首先,我们要理解Socket的基本概念。Socket是TCP/IP协议族的一部分,它为应用程序提供了网络通信的接口。在Java中,`java.net....

    java代码实现文件上传和下载

    在java代码中实现文件的上传和下载,通过页面的file文件上传到java代码段,获取文件的大小和名字

    android使用socket上传、下载文件

    本篇将详细讲解如何在Android应用中使用Socket进行文件的上传和下载操作。 首先,理解Socket的基本概念:Socket是应用程序与网络协议之间的接口,它允许两个网络应用程序通过TCP/IP协议进行通信。在Android中,我们...

    Android上传单文件和多文件(后台使用MultipartFile)

    对于大文件上传,可能需要分块上传,或者使用断点续传技术。同时,为了提高用户体验,可以考虑使用异步任务或协程来处理文件上传,避免阻塞UI线程。 在实际开发中,Android单文件和多文件上传是一个相对复杂的流程...

    Android-Java代码解析class文件

    在Android开发过程中,Java代码是基础,而深入理解编译后的class文件对于优化代码和调试异常至关重要。class文件是Java源代码经过JVM(Java Virtual Machine)编译后的二进制格式,它包含了类的结构、方法、变量等...

    Java文件上传下载实例(含详细注释)

    - 为了防止内存溢出,大文件上传可能需要分块处理,或者使用临时文件存储。 - 文件下载应考虑性能,比如使用流式处理避免一次性加载整个文件到内存。 7. **错误处理与反馈**: - 实例中可能包含如何向用户返回...

    Android文件上传.rar

    在Android平台上进行文件上传是一项常见的任务,特别是在开发涉及用户交互的应用程序时,如社交媒体应用、云存储服务等。本文将详细解析如何在Android系统中实现文件上传,主要围绕"Android文件上传"这一主题展开,...

Global site tag (gtag.js) - Google Analytics