zoukankan      html  css  js  c++  java
  • Java 文件分块上传客户端和服务器端源代码

    Java 文件分块上传客户端源代码  http://blog.csdn.net/defonds/article/details/8575893

    MIME协议(中文版).doc

            本博客介绍如何进行文件的分块上传。本文侧重介绍客户端,服务器端请参考博客《Java 文件分块上传服务器端源代码》。建议读者朋友在阅读本文代码前先了解一下 MIME 协议。

            所谓分块上传并非把大文件进行物理分块,然后挨个上传,而是依次读取大文件的一部分文件流进行上传。分块,倒不如说分流比较切实。本文通过一个项目中的示例,说明使用 Apache 的 HttpComponents/HttpClient 对大文件进行分块上传的过程。示例使用的版本是 HttpComponents Client 4.2.1。
            本文仅以一小 demo 功能性地解释 HttpComponents/HttpClient 分块上传,没有考虑 I/O 关闭、多线程等资源因素,读者可以根据自己的项目酌情处理。
            本文核心思想及流程:以 100 MB 大小为例,大于 100 MB 的进行分块上传,否则整块上传。对于大于 100 MB 的文件,又以 100 MB 为单位进行分割,保证每次以不大于 100 MB 的大小进行上传。比如 304 MB 的一个文件会分为 100 MB、100 MB、100 MB、4 MB 等四块依次上传。第一次读取 0 字节开始的 100 MB 个字节,上传;第二次读取第 100 MB 字节开始的 100 MB 个字节,上传;第三次读取第 200 MB 字节开始的 100 MB 个字节,上传;第四次读取最后剩下的 4 MB 个字节进行上传。

            自定义的 ContentBody 源码如下,其中定义了流的读取和输出:

    [html] view plaincopy
    1. package com.defonds.rtupload.common.util.block;  
    2.   
    3. import java.io.File;  
    4. import java.io.IOException;  
    5. import java.io.OutputStream;  
    6. import java.io.RandomAccessFile;  
    7.   
    8. import org.apache.http.entity.mime.content.AbstractContentBody;  
    9.   
    10. import com.defonds.rtupload.GlobalConstant;  
    11.   
    12. public class BlockStreamBody extends AbstractContentBody {  
    13.       
    14.     //给MultipartEntity看的2个参数  
    15.     private long blockSize = 0;//本次分块上传的大小  
    16.     private String fileName = null;//上传文件名  
    17.     //writeTo需要的3个参数  
    18.     private int blockNumber = 0blockIndex = 0;//blockNumber分块数;blockIndex当前第几块  
    19.     private File targetFile = null;//要上传的文件  
    20.   
    21.     private BlockStreamBody(String mimeType) {  
    22.         super(mimeType);  
    23.         // TODO Auto-generated constructor stub  
    24.     }  
    25.       
    26.     /**  
    27.      * 自定义的ContentBody构造子  
    28.      * @param blockNumber分块数  
    29.      * @param blockIndex当前第几块  
    30.      * @param targetFile要上传的文件  
    31.      */  
    32.     public BlockStreamBody(int blockNumber, int blockIndex, File targetFile) {  
    33.         this("application/octet-stream");  
    34.         this.blockNumber = blockNumber;//blockNumber初始化  
    35.         this.blockIndex = blockIndex;//blockIndex初始化  
    36.         this.targetFile = targetFile;//targetFile初始化  
    37.         this.fileName = targetFile.getName();//fileName初始化  
    38.         //blockSize初始化  
    39.         if (blockIndex < blockNumber) {//不是最后一块,那就是固定大小了  
    40.             this.blockSize = GlobalConstant.CLOUD_API_LOGON_SIZE;  
    41.         } else {//最后一块  
    42.             this.blockSize = targetFile.length() - GlobalConstant.CLOUD_API_LOGON_SIZE * (blockNumber - 1);  
    43.         }  
    44.     }  
    45.   
    46.     @Override  
    47.     public void writeTo(OutputStream out) throws IOException {  
    48.         byte b[] = new byte[1024];//暂存容器  
    49.         RandomAccessFile raf  = new RandomAccessFile(targetFile, "r");//负责读取数据  
    50.         if (blockIndex == 1) {//第一块  
    51.             int n = 0;  
    52.             long readLength = 0;//记录已读字节数  
    53.             while (readLength <= blockSize - 1024) {//大部分字节在这里读取  
    54.                 n = raf.read(b, 0, 1024);  
    55.                 readLength += 1024;  
    56.                 out.write(b, 0, n);  
    57.             }  
    58.             if (readLength <= blockSize) {//余下的不足 1024 个字节在这里读取  
    59.                 n = raf.read(b, 0, (int)(blockSize - readLength));  
    60.                 out.write(b, 0, n);  
    61.             }  
    62.         } else if (blockIndex < blockNumber) {//既不是第一块,也不是最后一块  
    63.             raf.seek(GlobalConstant.CLOUD_API_LOGON_SIZE * (blockIndex - 1));//跳过前[块数*固定大小 ]个字节  
    64.             int n = 0;  
    65.             long readLength = 0;//记录已读字节数  
    66.             while (readLength <= blockSize - 1024) {//大部分字节在这里读取  
    67.                 n = raf.read(b, 0, 1024);  
    68.                 readLength += 1024;  
    69.                 out.write(b, 0, n);  
    70.             }  
    71.             if (readLength <= blockSize) {//余下的不足 1024 个字节在这里读取  
    72.                 n = raf.read(b, 0, (int)(blockSize - readLength));  
    73.                 out.write(b, 0, n);  
    74.             }  
    75.         } else {//最后一块  
    76.             raf.seek(GlobalConstant.CLOUD_API_LOGON_SIZE * (blockIndex - 1));//跳过前[块数*固定大小 ]个字节  
    77.             int n = 0;  
    78.             while ((n = raf.read(b, 0, 1024)) != -1) {  
    79.                 out.write(b, 0, n);  
    80.             }  
    81.         }  
    82.           
    83.         //TODO 最后不要忘掉关闭out/raf  
    84.     }  
    85.       
    86.     @Override  
    87.     public String getCharset() {  
    88.         // TODO Auto-generated method stub  
    89.         return null;  
    90.     }  
    91.       
    92.     @Override  
    93.     public String getTransferEncoding() {  
    94.         // TODO Auto-generated method stub  
    95.         return "binary";  
    96.     }  
    97.       
    98.     @Override  
    99.     public String getFilename() {  
    100.         // TODO Auto-generated method stub  
    101.         return fileName;  
    102.     }  
    103.   
    104.     @Override  
    105.     public long getContentLength() {  
    106.         // TODO Auto-generated method stub  
    107.         return blockSize;  
    108.     }  
    109.   
    110. }  


            在自定义的 HttpComponents/HttpClient 工具类 HttpClient4Util 里进行分块上传的封装:

    [java] view plaincopy
    1. public static String restPost(String serverURL, File targetFile,Map<String, String> mediaInfoMap){  
    2.   
    3.     String content ="";  
    4.     try {  
    5.         DefaultHttpClient httpClient = new DefaultHttpClient();  
    6.         HttpPost post = new HttpPost(serverURL +"?");  
    7.         httpClient.getParams().setParameter("http.socket.timeout",60*60*1000);  
    8.         MultipartEntity mpEntity = new MultipartEntity();  
    9.         List<String> keys = new ArrayList<String>(mediaInfoMap.keySet());  
    10.         Collections.sort(keys, String.CASE_INSENSITIVE_ORDER);  
    11.         for (Iterator<String> iterator = keys.iterator(); iterator.hasNext();) {  
    12.             String key = iterator.next();  
    13.             if (StringUtils.isNotBlank(mediaInfoMap.get(key))) {  
    14.                 mpEntity.addPart(key, new StringBody(mediaInfoMap.get(key)));  
    15.             }  
    16.         }  
    17.           
    18.         if(targetFile!=null&&targetFile.exists()){  
    19.             ContentBody contentBody = new FileBody(targetFile);  
    20.             mpEntity.addPart("file", contentBody);  
    21.         }  
    22.         post.setEntity(mpEntity);  
    23.   
    24.           
    25.         HttpResponse response = httpClient.execute(post);  
    26.         content = EntityUtils.toString(response.getEntity());  
    27.         httpClient.getConnectionManager().shutdown();  
    28.     } catch (Exception e) {  
    29.         e.printStackTrace();  
    30.     }  
    31.     System.out.println("=====RequestUrl========================== "  
    32.             +getRequestUrlStrRest(serverURL, mediaInfoMap).replaceAll("&fmt=json"""));  
    33.     System.out.println("=====content========================== "+content);  
    34.     return content.trim();  
    35. }  

            其中 "file" 是分块上传服务器对分块文件参数定义的名字。细心的读者会发现,整块文件上传直接使用 Apache 官方的 InputStreamBody,而分块才使用自定义的 BlockStreamBody。

            最后调用 HttpClient4Util 进行上传:

    [java] view plaincopy
    1. public static Map<String, String> uploadToDrive(  
    2.         Map<String, String> params, String domain) {  
    3.   
    4.     File targetFile = new File(params.get("filePath"));  
    5.     long targetFileSize = targetFile.length();  
    6.     int mBlockNumber = 0;  
    7.     if (targetFileSize < GlobalConstant.CLOUD_API_LOGON_SIZE) {  
    8.         mBlockNumber = 1;  
    9.     } else {  
    10.         mBlockNumber = (int) (targetFileSize / GlobalConstant.CLOUD_API_LOGON_SIZE);  
    11.         long someExtra = targetFileSize  
    12.                 % GlobalConstant.CLOUD_API_LOGON_SIZE;  
    13.         if (someExtra > 0) {  
    14.             mBlockNumber++;  
    15.         }  
    16.     }  
    17.     params.put("blockNumber", Integer.toString(mBlockNumber));  
    18.   
    19.     if (domain != null) {  
    20.         LOG.debug("Drive---domain=" + domain);  
    21.         LOG.debug("drive---url=" + "http://" + domain + "/sync"  
    22.                 + GlobalConstant.CLOUD_API_PRE_UPLOAD_PATH);  
    23.     } else {  
    24.         LOG.debug("Drive---domain=null");  
    25.     }  
    26.     String responseBodyStr = HttpClient4Util.getRest("http://" + domain  
    27.             + "/sync" + GlobalConstant.CLOUD_API_PRE_UPLOAD_PATH, params);  
    28.   
    29.     ObjectMapper mapper = new ObjectMapper();  
    30.     DrivePreInfo result;  
    31.     try {  
    32.         result = mapper.readValue(responseBodyStr, ArcDrivePreInfo.class);  
    33.     } catch (IOException e) {  
    34.         LOG.error("Drive.preUploadToArcDrive error.", e);  
    35.         throw new RtuploadException(GlobalConstant.ERROR_CODE_13001);// TODO  
    36.     }  
    37.     // JSONObject jsonObject = JSONObject.fromObject(responseBodyStr);  
    38.     if (Integer.valueOf(result.getRc()) == 0) {  
    39.         int uuid = result.getUuid();  
    40.         String upsServerUrl = result.getUploadServerUrl().replace("https",  
    41.                 "http");  
    42.         if (uuid != -1) {  
    43.             upsServerUrl = upsServerUrl  
    44.                     + GlobalConstant.CLOUD_API_UPLOAD_PATH;  
    45.             params.put("uuid", String.valueOf(uuid));  
    46.   
    47.             for (int i = 1; i <= mBlockNumber; i++) {  
    48.                 params.put("blockIndex""" + i);  
    49.                 HttpClient4Util.restPostBlock(upsServerUrl, targetFile,  
    50.                         params);//  
    51.             }  
    52.         }  
    53.     } else {  
    54.         throw new RtuploadException(GlobalConstant.ERROR_CODE_13001);// TODO  
    55.     }  
    56.     return null;  
    57. }  

            其中 params 这个 Map 里封装的是服务器分块上传所需要的一些参数,而上传块数也在这里进行确定。
            本文中的示例经本人测试能够上传大文件成功,诸如 *.mp4 的文件上传成功没有出现任何问题。如果读者朋友测试时遇到问题无法上传成功,请在博客后跟帖留言,大家共同交流下。本文示例肯定还存在很多不足之处,如果读者朋友发现还请留言指出,笔者先行谢过了。



     

    Java 文件分块上传服务器端源代码 http://blog.csdn.net/defonds/article/details/8647129

     

     本博客将介绍如何进行文件的分块上传。如果读者还想了解文件的“分块”下载相关内容可以去参考博客《Java 服务器端支持断点续传的源代码【支持快车、迅雷】》。
            本文侧重介绍服务器端,客户端端请参考本篇博客的姊妹篇《Java 文件分块上传客户端源代码》,关于分块上传的思想及其流程,已在该博客中进行了详细说明,这里不再赘述。

            直接上代码。接收客户端 HTTP 分块上传请求的 Spring MVC 控制器源代码如下:

    [java] view plaincopy
    1. @Controller  
    2. public class UploadController extends BaseController {  
    3.   
    4.     private static final Log log = LogFactory.getLog(UploadController.class);  
    5.     private UploadService uploadService;  
    6.     private AuthService authService;  
    7.   
    8.     /** 
    9.      * 大文件分成小文件块上传,一次传递一块,最后一块上传成功后,将合并所有已经上传的块,保存到File Server 
    10.      * 上相应的位置,并返回已经成功上传的文件的详细属性. 当最后一块上传完毕,返回上传成功的信息。此时用getFileList查询该文件, 
    11.      * 该文件的uploadStatus为2。client请自行处理该状态下文件如何显示。(for UPS Server) 
    12.      *  
    13.      */  
    14.     @RequestMapping("/core/v1/file/upload")  
    15.     @ResponseBody  
    16.     public Object upload(HttpServletResponse response,  
    17.             @RequestParam(value = "client_id", required = false) String appkey,  
    18.             @RequestParam(value = "sig", required = false) String appsig,  
    19.             @RequestParam(value = "token", required = false) String token,  
    20.             @RequestParam(value = "uuid", required = false) String uuid,  
    21.             @RequestParam(value = "block", required = false) String blockIndex,  
    22.             @RequestParam(value = "file", required = false) MultipartFile multipartFile,  
    23.             @RequestParam Map<String, String> parameters) {  
    24.   
    25.         checkEmpty(appkey, BaseException.ERROR_CODE_16002);  
    26.         checkEmpty(token, BaseException.ERROR_CODE_16007);  
    27.         checkEmpty(uuid, BaseException.ERROR_CODE_20016);  
    28.         checkEmpty(blockIndex, BaseException.ERROR_CODE_20006);  
    29.         checkEmpty(appsig, BaseException.ERROR_CODE_10010);  
    30.         if (multipartFile == null) {  
    31.             throw new BaseException(BaseException.ERROR_CODE_20020);// 上传文件不存在  
    32.         }  
    33.         Long uuidL = parseLong(uuid, BaseException.ERROR_CODE_20016);  
    34.         Integer blockIndexI = parseInt(blockIndex, BaseException.ERROR_CODE_20006);  
    35.           
    36.         Map<String, Object> appMap = getAuthService().validateSigature(parameters);  
    37.   
    38.         AccessToken accessToken = CasUtil.checkAccessToken(token, appMap);  
    39.         Long uid = accessToken.getUid();  
    40.         String bucketUrl = accessToken.getBucketUrl();  
    41.         // 从上传目录拷贝文件到工作目录  
    42.         String fileAbsulutePath = null;  
    43.         try {  
    44.             fileAbsulutePath = this.copyFile(multipartFile.getInputStream(), multipartFile.getOriginalFilename());  
    45.         } catch (IOException ioe) {  
    46.             log.error(ioe.getMessage(), ioe);  
    47.             throw new BaseException(BaseException.ERROR_CODE_20020);// 上传文件不存在  
    48.         }  
    49.         File uploadedFile = new File(Global.UPLOAD_TEMP_DIR + fileAbsulutePath);  
    50.         checkEmptyFile(uploadedFile);// file 非空验证  
    51.   
    52.         Object rs = uploadService.upload(uuidL, blockIndexI, uid, uploadedFile, bucketUrl);  
    53.         setHttpStatusOk(response);  
    54.         return rs;  
    55.     }  
    56.   
    57.     // TODO 查看下这里是否有问题  
    58.     // 上传文件非空验证  
    59.     private void checkEmptyFile(File file) {  
    60.         if (file == null || file.getAbsolutePath() == null) {  
    61.             throw new BaseException(BaseException.ERROR_CODE_20020);// 上传文件不存在  
    62.         }  
    63.     }  
    64.   
    65.     /** 
    66.      * 写文件到本地文件夹 
    67.      *  
    68.      * @throws IOException 
    69.      *             返回生成的文件名 
    70.      */  
    71.     private String copyFile(InputStream inputStream, String fileName) {  
    72.         OutputStream outputStream = null;  
    73.         String tempFileName = null;  
    74.         int pointPosition = fileName.lastIndexOf(".");  
    75.         if (pointPosition < 0) {// myvedio  
    76.             tempFileName = UUID.randomUUID().toString();// 94d1d2e0-9aad-4dd8-a0f6-494b0099ff26  
    77.         } else {// myvedio.flv  
    78.             tempFileName = UUID.randomUUID() + fileName.substring(pointPosition);// 94d1d2e0-9aad-4dd8-a0f6-494b0099ff26.flv  
    79.         }  
    80.         try {  
    81.             outputStream = new FileOutputStream(Global.UPLOAD_TEMP_DIR + tempFileName);  
    82.             int readBytes = 0;  
    83.             byte[] buffer = new byte[10000];  
    84.             while ((readBytes = inputStream.read(buffer, 010000)) != -1) {  
    85.                 outputStream.write(buffer, 0, readBytes);  
    86.             }  
    87.             return tempFileName;  
    88.         } catch (IOException ioe) {  
    89.             // log.error(ioe.getMessage(), ioe);  
    90.             throw new BaseException(BaseException.ERROR_CODE_20020);// 上传文件不存在  
    91.         } finally {  
    92.             if (outputStream != null) {  
    93.                 try {  
    94.                     outputStream.close();  
    95.                 } catch (IOException e) {  
    96.                 }  
    97.             }  
    98.             if (inputStream != null) {  
    99.                 try {  
    100.                     inputStream.close();  
    101.                 } catch (IOException e) {  
    102.                 }  
    103.             }  
    104.   
    105.         }  
    106.   
    107.     }  
    108.   
    109.     /** 
    110.      * 测试此服务是否可用 
    111.      *  
    112.      * @param response 
    113.      * @return 
    114.      * @author zwq7978 
    115.      */  
    116.     @RequestMapping("/core/v1/file/testServer")  
    117.     @ResponseBody  
    118.     public Object testServer(HttpServletResponse response) {  
    119.         setHttpStatusOk(response);  
    120.         return Global.SUCCESS_RESPONSE;  
    121.     }  
    122.   
    123.     public UploadService getUploadService() {  
    124.         return uploadService;  
    125.     }  
    126.   
    127.     public void setUploadService(UploadService uploadService) {  
    128.         this.uploadService = uploadService;  
    129.     }  
    130.   
    131.     public void setAuthService(AuthService authService) {  
    132.         this.authService = authService;  
    133.     }  
    134.   
    135.     public AuthService getAuthService() {  
    136.         return authService;  
    137.     }  
    138.   
    139. }  

            比如要上传的文件是 test450k.mp4。对照《Java 文件分块上传客户端源代码》中分块上传服务器对分块文件参数定义的名字"file",upload 方法里使用的是 MultipartFile 接收该对象。对于每次的 HTTP 请求,使用 copyFile 方法将文件流输出到服务器本地的一个临时文件夹里,比如作者的是 D:/defonds/syncPath/uploadTemp,该文件下会有 50127019-b63b-4a54-8f53-14efd1e58ada.mp4 临时文件生成用于保存上传文件流。

            分块依次上传。当所有块都上传完毕之后,将这些临时文件都转移到服务器指定目录中,比如作者的这个目录是 D:/defonds/syncPath/file,在该文件夹下会有/1/temp_dir_5_1 目录生成,而 uploadTemp 的临时文件则被挨个转移到这个文件夹下,生成形如 5.part0001 的文件。以下是文件转移的源代码:

    [java] view plaincopy
    1. /** 
    2.  * 把所有块从临时文件目录移到指定本地目录或S2/S3 
    3.  *  
    4.  * @param preUpload 
    5.  */  
    6. private void moveBlockFiles(BlockPreuploadFileInfo preUpload) {  
    7.     @SuppressWarnings("unchecked")  
    8.     String[] s3BlockUrl=new String[preUpload.getBlockNumber()];  
    9.     String[] localBlockUrl=new String[preUpload.getBlockNumber()];//本地的块文件路径    以便以后删除  
    10.     List<BlockUploadInfo> blocks = (List<BlockUploadInfo>) getBaseDao().queryForList(  
    11.             "upload.getBlockUploadFileByUuid", preUpload.getUuid());  
    12.               
    13.     String tempDirName = SyncUtil.getTempDirName(preUpload.getUuid(), preUpload.getUid());  
    14.     String parentPath = Global.UPLOAD_ABSOLUTE_PAHT_ + Global.PATH_SEPARATIVE_SIGN  
    15.             + String.valueOf(preUpload.getUid());  
    16.     String dirPath = parentPath + Global.PATH_SEPARATIVE_SIGN + tempDirName;  
    17.     new File(dirPath).mkdirs();//创建存放块文件的文件夹 (本地)  
    18.     int j=0;  
    19.     for (BlockUploadInfo info : blocks) {  
    20.         try {  
    21.             String strBlockIndex = createStrBlockIndex(info.getBlockIndex());  
    22.             String suffixPath = preUpload.getUuid() + ".part" + strBlockIndex;  
    23.             String tempFilePath = info.getTempFile();  
    24.             File tempFile = new File(tempFilePath);  
    25.             File tmpFile = new File(dirPath + suffixPath);  
    26.             if (tmpFile.exists()) {  
    27.                 FileUtils.deleteQuietly(tmpFile);  
    28.             }  
    29.             FileUtils.moveFile(tempFile, tmpFile);  
    30.             localBlockUrl[j]=dirPath + suffixPath;  
    31.             j++;  
    32.             info.setStatus(Global.MOVED_TO_NEWDIR);  
    33.             getBaseDao().update("upload.updateBlockUpload", info);  
    34.             if (log.isInfoEnabled())  
    35.                 log.info(preUpload.getUuid() + " " + info.getBuId() + " moveBlockFiles");  
    36.         } catch (IOException e) {  
    37.             log.error(e.getMessage(), e);  
    38.             throw new BaseException("file not found");  
    39.         }  
    40.     }  
    41.     preUpload.setLocalBlockUrl(localBlockUrl);  
    42.     preUpload.setDirPath(dirPath);  
    43.     preUpload.setStatus(Global.MOVED_TO_NEWDIR);  
    44.     getBaseDao().update("upload.updatePreUploadInfo", preUpload);  
    45. }  
    46.   
    47. private String createStrBlockIndex(int blockIndex) {  
    48.     String strBlockIndex;  
    49.     if (blockIndex < 10) {  
    50.         strBlockIndex = "000" + blockIndex;  
    51.     } else if (10 <= blockIndex && blockIndex < 100) {  
    52.         strBlockIndex = "00" + blockIndex;  
    53.     } else if (100 <= blockIndex && blockIndex < 1000) {  
    54.         strBlockIndex = "0" + blockIndex;  
    55.     } else {  
    56.         strBlockIndex = "" + blockIndex;  
    57.     }  
    58.     return strBlockIndex;  
    59. }  

            最后是文件的组装源代码:

    [java] view plaincopy
    1. /** 
    2.  * 组装文件 
    3.  *  
    4.  */  
    5. private void assembleFileWithBlock(BlockPreuploadFileInfo preUpload) {  
    6.     String dirPath = preUpload.getDirPath();  
    7.     // 开始在指定目录组装文件  
    8.     String uploadedUrl = null;  
    9.     String[] separatedFiles;  
    10.     String[][] separatedFilesAndSize;  
    11.     int fileNum = 0;  
    12.     File file = new File(dirPath);  
    13.     separatedFiles = file.list();  
    14.     separatedFilesAndSize = new String[separatedFiles.length][2];  
    15.     Arrays.sort(separatedFiles);  
    16.     fileNum = separatedFiles.length;  
    17.     for (int i = 0; i < fileNum; i++) {  
    18.         separatedFilesAndSize[i][0] = separatedFiles[i];  
    19.         String fileName = dirPath + separatedFiles[i];  
    20.         File tmpFile = new File(fileName);  
    21.         long fileSize = tmpFile.length();  
    22.         separatedFilesAndSize[i][1] = String.valueOf(fileSize);  
    23.     }  
    24.   
    25.     RandomAccessFile fileReader = null;  
    26.     RandomAccessFile fileWrite = null;  
    27.     long alreadyWrite = 0;  
    28.     int len = 0;  
    29.     byte[] buf = new byte[1024];  
    30.     try {  
    31.         uploadedUrl = Global.UPLOAD_ABSOLUTE_PAHT_ + Global.PATH_SEPARATIVE_SIGN + preUpload.getUid() + Global.PATH_SEPARATIVE_SIGN + preUpload.getUuid();  
    32.         fileWrite = new RandomAccessFile(uploadedUrl, "rw");  
    33.         for (int i = 0; i < fileNum; i++) {  
    34.             fileWrite.seek(alreadyWrite);  
    35.             // 读取  
    36.             fileReader = new RandomAccessFile((dirPath + separatedFilesAndSize[i][0]), "r");  
    37.             // 写入  
    38.             while ((len = fileReader.read(buf)) != -1) {  
    39.                 fileWrite.write(buf, 0, len);  
    40.             }  
    41.             fileReader.close();  
    42.             alreadyWrite += Long.parseLong(separatedFilesAndSize[i][1]);  
    43.         }  
    44.         fileWrite.close();  
    45.         preUpload.setStatus(Global.ASSEMBLED);  
    46.         preUpload.setServerPath(uploadedUrl);  
    47.         getBaseDao().update("upload.updatePreUploadInfo", preUpload);  
    48.           
    49.         if(Global.BLOCK_UPLOAD_TO!=Global.BLOCK_UPLOAD_TO_LOCAL)  
    50.         {  
    51.         //组装完毕没有问题  删除掉S2/S3上的block  
    52.         String[] path=preUpload.getS3BlockUrl();  
    53.         for (String string : path) {  
    54.             try {  
    55.                 if(Global.BLOCK_UPLOAD_TO==Global.BLOCK_UPLOAD_TO_S2)  
    56.                 {  
    57.                 S2Util.deleteFile(preUpload.getBucketUrl(), string);  
    58.                 }else  
    59.                 {  
    60.                 S3Util.deleteFile(preUpload.getBucketUrl(), string);  
    61.                 }  
    62.             } catch (Exception e) {  
    63.                 log.error(e.getMessage(), e);  
    64.             }  
    65.         }  
    66.         }  
    67.         if (log.isInfoEnabled())  
    68.             log.info(preUpload.getUuid() + " assembleFileWithBlock");  
    69.     } catch (IOException e) {  
    70.         log.error(e.getMessage(), e);  
    71.         try {  
    72.             if (fileReader != null) {  
    73.                 fileReader.close();  
    74.             }  
    75.             if (fileWrite != null) {  
    76.                 fileWrite.close();  
    77.             }  
    78.         } catch (IOException ex) {  
    79.             log.error(e.getMessage(), e);  
    80.         }  
    81.     }  
    82.   
    83. }  

            BlockPreuploadFileInfo 是我们自定义的业务文件处理 bean。
            OK,分块上传的服务器、客户端源代码及其工作流程至此已全部介绍完毕,以上源代码全部是经过项目实践过的,大部分现在仍运行于一些项目之中。有兴趣的朋友可以自己动手,将以上代码自行改造,看看能否运行成功。如果遇到问题可以在本博客下跟帖留言,大家一起讨论讨论。

  • 相关阅读:
    一周之内了解一个行业的方法
    du命令 实现Linux 某个文件夹下的文件按大小排序
    蝴蝶效应、青蛙现象、鳄鱼法则、鲇鱼效应.......
    MYSQ提高L查询效率的策略总结
    12个高矮不同的人,排成两排(catalan数)
    四人过桥、三盏灯 三个开关 的答案
    给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。
    一个int 数组,里面数据无任何限制,要求求出所有这样的数a[i],其左边的数都小于等于它,右边的数都大于等于它。能否只用一个额外数组和少量其它空间实现。
    二分检索(查找)的各种变种
    排序算法稳定性
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13318244.html
Copyright © 2011-2022 走看看