当前位置:   article > 正文

android 大文件分割上传(分块上传)_android 文件分片上传框架

android 文件分片上传框架

由于android自身的原因,对大文件(如视频文件)的操作很容易造成OOM,即:Dalvik堆内存溢出,利用文件分割将大文件分割为小文件可以解决问题。

文件分割后分多次请求服务。

  1. //文件分割上传
  2. public void cutFileUpload(String fileType,String filePath)
  3. {
  4. try
  5. {
  6. FileAccessI fileAccessI = new FileAccessI(filePath, 0);
  7. Long nStartPos = 0l;
  8. Long length = fileAccessI.getFileLength();
  9. int mBufferSize = 1024 * 100; //每次处理1024 * 100字节
  10. byte[] buffer = new byte[mBufferSize];
  11. FileAccessI.Detail detail;
  12. long nRead = 0l;
  13. String vedioFileName = Usual.f_getUUID(); //分配一个文件名
  14. long nStart = nStartPos;
  15. int i = 0;
  16. while (nStart < length)
  17. {
  18. detail = fileAccessI.getContent(nStart);
  19. nRead = detail.length;
  20. buffer = detail.b;
  21. JSONObject mInDataJson = new JSONObject();
  22. mInDataJson.put("a", "282");
  23. mInDataJson.put("FileName", vedioFileName);
  24. mInDataJson.put("start", nStart); //服务端获取开始文章进行写文件
  25. mInDataJson.put("filetype", fileType);
  26. nStart += nRead;
  27. nStartPos = nStart;
  28. String url = UsualA.f_getXmlSOAUrl(UsualA.mServiceFastByteUrl, "n.uploadvedio", mInDataJson.toString(),
  29. "282");
  30. HttpFastUtil.f_httpPostByte(url, buffer, false);
  31. }
  32. }
  33. catch (Exception e)
  34. {
  35. }

文件分割类

  1. package ishitong.mppsp.android.util;
  2. import java.io.*;
  3. public class FileAccessI implements Serializable
  4. {
  5. RandomAccessFile oSavedFile;
  6. long nPos;
  7. public FileAccessI() throws IOException
  8. {
  9. this("", 0);
  10. }
  11. public FileAccessI(String sName, long nPos) throws IOException
  12. {
  13. oSavedFile = new RandomAccessFile(sName, "rw");//创建一个随机访问文件类,可读写模式
  14. this.nPos = nPos;
  15. oSavedFile.seek(nPos);
  16. }
  17. public synchronized int write(byte[] b, int nStart, int nLen)
  18. {
  19. int n = -1;
  20. try
  21. {
  22. oSavedFile.write(b, nStart, nLen);
  23. n = nLen;
  24. }
  25. catch (IOException e)
  26. {
  27. e.printStackTrace();
  28. }
  29. return n;
  30. }
  31. //每次读取102400字节
  32. public synchronized Detail getContent(long nStart)
  33. {
  34. Detail detail = new Detail();
  35. detail.b = new byte[102400];
  36. try
  37. {
  38. oSavedFile.seek(nStart);
  39. detail.length = oSavedFile.read(detail.b);
  40. }
  41. catch (IOException e)
  42. {
  43. e.printStackTrace();
  44. }
  45. return detail;
  46. }
  47. public class Detail
  48. {
  49. public byte[] b;
  50. public int length;
  51. }
  52. //获取文件长度
  53. public long getFileLength()
  54. {
  55. Long length = 0l;
  56. try
  57. {
  58. length = oSavedFile.length();
  59. }
  60. catch (IOException e)
  61. {
  62. // TODO Auto-generated catch block
  63. e.printStackTrace();
  64. }
  65. return length;
  66. }
  67. }

服务端获得分割的文件,利用RandomAccessFile进行文件整理

  1. /**
  2. * 音视频图片处理
  3. * @param mStr
  4. * @return
  5. * @throws Exception
  6. */
  7. public static String f_uploadVedio(String mStr) throws Exception
  8. {
  9. String mResult = Usual.mEmpty;
  10. String fileType = Usual.mEmpty;
  11. int startPosL = 0;
  12. RandomAccessFile oSavedFile = null;
  13. JSONObject jsonObject = new JSONObject(mStr);
  14. String vedioJsonStr = jsonObject.getString("VEDIO");
  15. byte[] vedioBytes = Usual.f_fromBase64String(vedioJsonStr);
  16. startPosL = (Integer) jsonObject.get("start"); //接收客户端的开始位置(文件读取到的字节大小)
  17. fileType = (String)jsonObject.getString("filetype");
  18. String fileName = (String)jsonObject.getString("FileName");
  19. if(fileType.equals("picture"))
  20. {
  21. oSavedFile = new RandomAccessFile("E:\\"+fileName+".jpg","rw");
  22. }
  23. else if(fileType.equals("photo"))
  24. {
  25. oSavedFile = new RandomAccessFile("E:\\"+fileName+".jpg","rw");
  26. }
  27. else if(fileType.equals("voice"))
  28. {
  29. oSavedFile = new RandomAccessFile("E:\\"+fileName+".mp3","rw");
  30. }
  31. else if(fileType.equals("video"))
  32. {
  33. oSavedFile = new RandomAccessFile("E:\\"+fileName+".mp4", "rw");
  34. }
  35. //设置标志位,标志文件存储的位置
  36. oSavedFile.seek(startPosL);
  37. oSavedFile.write(vedioBytes);
  38. oSavedFile.close();
  39. mResult = "000";
  40. return mResult;
  41. }

文件转为string字符串参考:

http://blog.csdn.net/jdsjlzx/article/details/51194719


用HttpUrlConnection模拟post表单进行文件上传平时很少使用,比较麻烦。

 

原理是: 分析文件上传的数据格式,然后根据格式构造相应的发送给服务器的字符串。

格式如下:这里的httppost123是我自己构造的字符串,可以是其他任何的字符串

----------httppost123 (\r\n)
Content-Disposition: form-data; name="img"; filename="t.txt" (\r\n)
Content-Type: application/octet-stream (\r\n)

(\r\n)

sdfsdfsdfsdfsdf (\r\n)
----------httppost123 (\r\n)
Content-Disposition: form-data; name="text" (\r\n)

(\r\n)

text tttt (\r\n)
----------httppost123-- (\r\n)
(\r\n)

 

上面的(\r\n)表示各个数据必须以(\r\n)结尾。

 

具体Java代码如下:

  1. import java.io.ByteArrayOutputStream;
  2. import java.io.DataOutputStream;
  3. import java.io.File;
  4. import java.io.FileInputStream;
  5. import java.io.InputStream;
  6. import java.net.HttpURLConnection;
  7. import java.net.SocketTimeoutException;
  8. import java.net.URL;
  9. import java.net.URLEncoder;
  10. import java.util.HashMap;
  11. import java.util.Iterator;
  12. import java.util.Map;
  13. import java.util.Set;
  14. import javax.imageio.ImageIO;
  15. import javax.imageio.ImageReader;
  16. import javax.imageio.stream.ImageInputStream;
  17. public class HttpPostUtil {
  18. URL url;
  19. HttpURLConnection conn;
  20. String boundary = "--------httppost123";
  21. Map<String, String> textParams = new HashMap<String, String>();
  22. Map<String, File> fileparams = new HashMap<String, File>();
  23. DataOutputStream ds;
  24. public HttpPostUtil(String url) throws Exception {
  25. this.url = new URL(url);
  26. }
  27. //重新设置要请求的服务器地址,即上传文件的地址。
  28. public void setUrl(String url) throws Exception {
  29. this.url = new URL(url);
  30. }
  31. //增加一个普通字符串数据到form表单数据中
  32. public void addTextParameter(String name, String value) {
  33. textParams.put(name, value);
  34. }
  35. //增加一个文件到form表单数据中
  36. public void addFileParameter(String name, File value) {
  37. fileparams.put(name, value);
  38. }
  39. // 清空所有已添加的form表单数据
  40. public void clearAllParameters() {
  41. textParams.clear();
  42. fileparams.clear();
  43. }
  44. // 发送数据到服务器,返回一个字节包含服务器的返回结果的数组
  45. public byte[] send() throws Exception {
  46. initConnection();
  47. try {
  48. conn.connect();
  49. } catch (SocketTimeoutException e) {
  50. // something
  51. throw new RuntimeException();
  52. }
  53. ds = new DataOutputStream(conn.getOutputStream());
  54. writeFileParams();
  55. writeStringParams();
  56. paramsEnd();
  57. InputStream in = conn.getInputStream();
  58. ByteArrayOutputStream out = new ByteArrayOutputStream();
  59. int b;
  60. while ((b = in.read()) != -1) {
  61. out.write(b);
  62. }
  63. conn.disconnect();
  64. return out.toByteArray();
  65. }
  66. //文件上传的connection的一些必须设置
  67. private void initConnection() throws Exception {
  68. conn = (HttpURLConnection) this.url.openConnection();
  69. conn.setDoOutput(true);
  70. conn.setUseCaches(false);
  71. conn.setConnectTimeout(10000); //连接超时为10秒
  72. conn.setRequestMethod("POST");
  73. conn.setRequestProperty("Content-Type",
  74. "multipart/form-data; boundary=" + boundary);
  75. }
  76. //普通字符串数据
  77. private void writeStringParams() throws Exception {
  78. Set<String> keySet = textParams.keySet();
  79. for (Iterator<String> it = keySet.iterator(); it.hasNext();) {
  80. String name = it.next();
  81. String value = textParams.get(name);
  82. ds.writeBytes("--" + boundary + "\r\n");
  83. ds.writeBytes("Content-Disposition: form-data; name=\"" + name
  84. + "\"\r\n");
  85. ds.writeBytes("\r\n");
  86. ds.writeBytes(encode(value) + "\r\n");
  87. }
  88. }
  89. //文件数据
  90. private void writeFileParams() throws Exception {
  91. Set<String> keySet = fileparams.keySet();
  92. for (Iterator<String> it = keySet.iterator(); it.hasNext();) {
  93. String name = it.next();
  94. File value = fileparams.get(name);
  95. ds.writeBytes("--" + boundary + "\r\n");
  96. ds.writeBytes("Content-Disposition: form-data; name=\"" + name
  97. + "\"; filename=\"" + encode(value.getName()) + "\"\r\n");
  98. ds.writeBytes("Content-Type: " + getContentType(value) + "\r\n");
  99. ds.writeBytes("\r\n");
  100. ds.write(getBytes(value));
  101. ds.writeBytes("\r\n");
  102. }
  103. }
  104. //获取文件的上传类型,图片格式为image/png,image/jpg等。非图片为application/octet-stream
  105. private String getContentType(File f) throws Exception {
  106. // return "application/octet-stream"; // 此行不再细分是否为图片,全部作为application/octet-stream 类型
  107. ImageInputStream imagein = ImageIO.createImageInputStream(f);
  108. if (imagein == null) {
  109. return "application/octet-stream";
  110. }
  111. Iterator<ImageReader> it = ImageIO.getImageReaders(imagein);
  112. if (!it.hasNext()) {
  113. imagein.close();
  114. return "application/octet-stream";
  115. }
  116. imagein.close();
  117. return "image/" + it.next().getFormatName().toLowerCase();//将FormatName返回的值转换成小写,默认为大写
  118. }
  119. //把文件转换成字节数组
  120. private byte[] getBytes(File f) throws Exception {
  121. FileInputStream in = new FileInputStream(f);
  122. ByteArrayOutputStream out = new ByteArrayOutputStream();
  123. byte[] b = new byte[1024];
  124. int n;
  125. while ((n = in.read(b)) != -1) {
  126. out.write(b, 0, n);
  127. }
  128. in.close();
  129. return out.toByteArray();
  130. }
  131. //添加结尾数据
  132. private void paramsEnd() throws Exception {
  133. ds.writeBytes("--" + boundary + "--" + "\r\n");
  134. ds.writeBytes("\r\n");
  135. }
  136. // 对包含中文的字符串进行转码,此为UTF-8。服务器那边要进行一次解码
  137. private String encode(String value) throws Exception{
  138. return URLEncoder.encode(value, "UTF-8");
  139. }
  140. public static void main(String[] args) throws Exception {
  141. HttpPostUtil u = new HttpPostUtil("http://localhost:3000/up_load");
  142. u.addFileParameter("img", new File(
  143. "D:\\素材\\圆月.jpg"));
  144. u.addTextParameter("text", "中文");
  145. byte[] b = u.send();
  146. String result = new String(b);
  147. System.out.println(result);
  148. }
  149. }

如果不把中文转成UTF-8的格式进行传输,则后台显示中文乱码。

同样,如果其他参数包含中文,则也应当先转码。

当然,具体什么编码要和后台接收的编码一致。


简单的demo:https://github.com/jdsjlzx/uploadFile


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/286425
推荐阅读
相关标签
  

闽ICP备14008679号