okhttp实现断点上传

前言

之前项目需要上传大文件的功能,上传大文件经常遇到上传一半由于网络或者其他一些原因上传失败。然后又得重新上传(很麻烦),所以就想能不能做个断点上传的功能。于是网上搜索,发现市面上很少有断点上传的案例,有找到一个案例也是采用SOCKET作为上传方式(大文件上传,不适合使用POST,GET形式)。由于大文件夹不适合http上传的方式,所以就想能不能把大文件切割成n块小文件,然后上传这些小文件,所有小文件全部上传成功后再在服务器上进行拼接。这样不就可以实现断点上传,又解决了http不适合上传大文件的难题了吗!!!

原理分析

*******Android客户端********

首先,android端调用服务器接口1,参数为filename(服务器标识判断是否上传过)

如果存在filename,说明之前上传过,则续传;如果没有,则从零开始上传。

然后,android端调用服务器接口2,传入参数name,chunck(传到第几块),chuncks(总共多少块)

      

*******服务器端********

接口一:根据上传文件名称filename 判断是否之前上传过,没有则返回客户端chunck=1,有则读取记录chunck并返回。

接口二:上传文件,如果上传块数chunck=chuncks,遍历所有块文件拼接成一个完整文件。

*******服务端源代码********

服务器接口1

@WebServlet(urlPatterns = { "/ckeckFileServlet" })
public class CkeckFileServlet extends HttpServlet {

    private FileUploadStatusServiceI statusService;
    String repositoryPath;
    String uploadPath;

    @Override
    public void init(ServletConfig config) throws ServletException {
        ServletContext servletContext = config.getServletContext();
        WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        statusService = (FileUploadStatusServiceI) context.getBean("fileUploadStatusServiceImpl");

        repositoryPath = FileUtils.getTempDirectoryPath();
        uploadPath = config.getServletContext().getRealPath("datas/uploader");
        File up = new File(uploadPath);
        if (!up.exists()) {
            up.mkdir();
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // TODO Auto-generated method stub

        String fileName = new String(req.getParameter("filename"));
        //String chunk = req.getParameter("chunk");
        //System.out.println(chunk);
        System.out.println(fileName);
        resp.setContentType("text/json; charset=utf-8");

        TfileUploadStatus file = statusService.get(fileName);

        try {
            if (file != null) {
                int schunk = file.getChunk();
                deleteFile(uploadPath + schunk + "_" + fileName);
                //long off = schunk * Long.parseLong(chunkSize);
                resp.getWriter().write("{\"off\":" + schunk + "}");

            } else {
                resp.getWriter().write("{\"off\":1}");
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

服务器接口2

@WebServlet(urlPatterns = { "/uploaderWithContinuinglyTransferring" })
public class UploaderServletWithContinuinglyTransferring extends HttpServlet {

    private static final long serialVersionUID = 1L;

    private FileUploadStatusServiceI statusService;
    String repositoryPath;
    String uploadPath;

    @Override
    public void init(ServletConfig config) throws ServletException {
        ServletContext servletContext = config.getServletContext();
        WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        statusService = (FileUploadStatusServiceI) context.getBean("fileUploadStatusServiceImpl");

        repositoryPath = FileUtils.getTempDirectoryPath();
        System.out.println("临时目录:" + repositoryPath);
        uploadPath = config.getServletContext().getRealPath("datas/uploader");
        System.out.println("目录:" + uploadPath);
        File up = new File(uploadPath);
        if (!up.exists()) {
            up.mkdir();
        }
    }
    @SuppressWarnings("unchecked")
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        Integer schunk = null;// 分割块数
        Integer schunks = null;// 总分割数
        String name = null;// 文件名
        BufferedOutputStream outputStream = null;
        if (ServletFileUpload.isMultipartContent(request)) {
            try {
                DiskFileItemFactory factory = new DiskFileItemFactory();
                factory.setSizeThreshold(1024);
                factory.setRepository(new File(repositoryPath));// 设置临时目录
                ServletFileUpload upload = new ServletFileUpload(factory);
                upload.setHeaderEncoding("UTF-8");
                upload.setSizeMax(5 * 1024 * 1024 * 1024);// 设置附近大小
                List<FileItem> items = upload.parseRequest(request);
                // 生成新文件名

                String newFileName = null;
                for (FileItem item : items) {
                    if (!item.isFormField()) {// 如果是文件类型
                        name = newFileName;// 获得文件名
                        if (name != null) {
                            String nFname = newFileName;
                            if (schunk != null) {
                                nFname = schunk + "_" + name;
                            }
                            File savedFile = new File(uploadPath, nFname);
                            item.write(savedFile);
                        }
                    } else {
                        // 判断是否带分割信息
                        if (item.getFieldName().equals("chunk")) {
                            schunk = Integer.parseInt(item.getString());
                            //System.out.println(schunk);
                        }
                        if (item.getFieldName().equals("chunks")) {
                            schunks = Integer.parseInt(item.getString());
                        }

                        if (item.getFieldName().equals("name")) {
                            newFileName = new String(item.getString());
                        }
                    }
                }
                //System.out.println(schunk + "/" + schunks);
                if (schunk != null && schunk == 1) {
                    TfileUploadStatus file = statusService.get(newFileName);
                    if (file != null) {
                        statusService.updateChunk(newFileName, schunk);
                    } else {
                        statusService.add(newFileName, schunk, schunks);
                    }

                } else {
                    TfileUploadStatus file = statusService.get(newFileName);
                    if (file != null) {
                        statusService.updateChunk(newFileName, schunk);
                    }
                }
                if (schunk != null && schunk.intValue() == schunks.intValue()) {
                    outputStream = new BufferedOutputStream(new FileOutputStream(new File(uploadPath, newFileName)));
                    // 遍历文件合并
                    for (int i = 1; i <= schunks; i++) {
                        //System.out.println("文件合并:" + i + "/" + schunks);
                        File tempFile = new File(uploadPath, i + "_" + name);
                        byte[] bytes = FileUtils.readFileToByteArray(tempFile);
                        outputStream.write(bytes);
                        outputStream.flush();
                        tempFile.delete();
                    }
                    outputStream.flush();
                }
                response.getWriter().write("{\"status\":true,\"newName\":\"" + newFileName + "\"}");
            } catch (FileUploadException e) {
                e.printStackTrace();
                response.getWriter().write("{\"status\":false}");
            } catch (Exception e) {
                e.printStackTrace();
                response.getWriter().write("{\"status\":false}");
            } finally {
                try {
                    if (outputStream != null)
                        outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

*******android端源码********

UploadTask 上传线程类
package com.mainaer.wjoklib.okhttp.upload;

import android.database.sqlite.SQLiteDatabase;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

import okhttp3.Headers;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * 上传线程
 *
 * @author hst
 * @date 2016/9/6 .
 */
    public class UploadTask implements Runnable {

    private static String FILE_MODE = "rwd";
    private OkHttpClient mClient;
    private SQLiteDatabase db;
    private UploadTaskListener mListener;

    private Builder mBuilder;
    private String id;// task id
    private String url;// file url
    private String fileName; // File name when saving
    private int uploadStatus;
    private int chunck, chuncks;//流块
    private int position;

    private int errorCode;
    static String BOUNDARY = "----------" + System.currentTimeMillis();
    public static final MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("multipart/form-data;boundary=" + BOUNDARY);

    private UploadTask(Builder builder) {
        mBuilder = builder;
        mClient = new OkHttpClient();
        this.id = mBuilder.id;
        this.url = mBuilder.url;
        this.fileName = mBuilder.fileName;
        this.uploadStatus = mBuilder.uploadStatus;
        this.chunck = mBuilder.chunck;
        this.setmListener(mBuilder.listener);
        // 以kb为计算单位
    }

    @Override
    public void run() {
        try {
            int blockLength = 1024 * 1024;
            File file = new File(Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator +fileName);
            if (file.length() % blockLength == 0) {
                chuncks = (int) file.length() / blockLength;
            } else {
                chuncks = (int) file.length() / blockLength + 1;

            }
            while (chunck <= chuncks&&uploadStatus!= UploadStatus.UPLOAD_STATUS_PAUSE&&uploadStatus!= UploadStatus.UPLOAD_STATUS_ERROR)
            {

                uploadStatus = UploadStatus.UPLOAD_STATUS_UPLOADING;
                Map<String, String> params = new HashMap<String, String>();
                params.put("name", fileName);
                params.put("chunks", chuncks + "");
                params.put("chunk", chunck + "");
                final byte[] mBlock = FileUtils.getBlock((chunck - 1) * blockLength, file, blockLength);
                MultipartBody.Builder builder = new MultipartBody.Builder()
                        .setType(MultipartBody.FORM);
                addParams(builder, params);
                RequestBody requestBody = RequestBody.create(MEDIA_TYPE_MARKDOWN, mBlock);
                builder.addFormDataPart("mFile", fileName, requestBody);
                Request request = new Request.Builder()
                        .url(url+ "uploaderWithContinuinglyTransferring")
                        .post(builder.build())
                        .build();
                Response response = null;
                response = mClient.newCall(request).execute();
                if (response.isSuccessful()) {
                    onCallBack();
                    chunck++;
                   /* if (chunck <= chuncks) {
                         run();
                    }*/
                }
                else
                {
                    uploadStatus = UploadStatus.UPLOAD_STATUS_ERROR;
                    onCallBack();
                }

            }
        } catch (IOException e) {
            uploadStatus = UploadStatus.UPLOAD_STATUS_ERROR;
            onCallBack();
            e.printStackTrace();
        }
    }

/*    *//**
     * 删除数据库文件和已经上传的文件
     *//*
    public void cancel() {
        if (mListener != null)
            mListener.onCancel(UploadTask.this);
    }*/

    /**
     * 分发回调事件到ui层
     */
    private void onCallBack() {
        mHandler.sendEmptyMessage(uploadStatus);
        // 同步manager中的task信息
        //UploadManager.getInstance().updateUploadTask(this);
    }

    Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            int code = msg.what;
            switch (code) {
                // 上传失败
                case UploadStatus.UPLOAD_STATUS_ERROR:
                    mListener.onError(UploadTask.this, errorCode,position);
                    break;
                // 正在上传
                case UploadStatus.UPLOAD_STATUS_UPLOADING:
                    mListener.onUploading(UploadTask.this, getDownLoadPercent(), position);
                 // 暂停上传
                    break;
                case UploadStatus.UPLOAD_STATUS_PAUSE:
                    mListener.onPause(UploadTask.this);
                    break;

            }
        }
    };

    private String getDownLoadPercent() {
        String baifenbi = "0";// 接受百分比的值
        if (chunck >= chuncks) {
            return "100";
        }
        double baiy = chunck * 1.0;
        double baiz = chuncks * 1.0;
        // 防止分母为0出现NoN
        if (baiz > 0) {
            double fen = (baiy / baiz) * 100;
            //NumberFormat nf = NumberFormat.getPercentInstance();
            //nf.setMinimumFractionDigits(2); //保留到小数点后几位
            // 百分比格式,后面不足2位的用0补齐
            //baifenbi = nf.format(fen);
            //注释掉的也是一种方法
            DecimalFormat df1 = new DecimalFormat("0");//0.00
            baifenbi = df1.format(fen);
        }
        return baifenbi;
    }

    private String getFileNameFromUrl(String url) {
        if (!TextUtils.isEmpty(url)) {
            return url.substring(url.lastIndexOf("/") + 1);
        }
        return System.currentTimeMillis() + "";
    }

    private void close(Closeable closeable) {
        try {
            closeable.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setClient(OkHttpClient mClient) {
        this.mClient = mClient;
    }

    public Builder getBuilder() {
        return mBuilder;
    }

    public void setBuilder(Builder builder) {
        this.mBuilder = builder;
    }

    public String getId() {
        if (!TextUtils.isEmpty(id)) {
        } else {
            id = url;
        }
        return id;
    }

    public String getUrl() {
        return url;
    }

    public String getFileName() {
        return fileName;
    }

    public void setUploadStatus(int uploadStatus) {
        this.uploadStatus = uploadStatus;
    }

    public int getUploadStatus() {
        return uploadStatus;
    }

    public void setmListener(UploadTaskListener mListener) {
        this.mListener = mListener;
    }

    public static class Builder {
        private String id;// task id
        private String url;// file url
        private String fileName; // File name when saving
        private int uploadStatus = UploadStatus.UPLOAD_STATUS_INIT;
        private int chunck;//第几块
        private UploadTaskListener listener;

        /**
         * 作为上传task开始、删除、停止的key值,如果为空则默认是url
         *
         * @param id
         * @return
         */
        public Builder setId(String id) {
            this.id = id;
            return this;
        }

        /**
         * 上传url(not null)
         *
         * @param url
         * @return
         */
        public Builder setUrl(String url) {
            this.url = url;
            return this;
        }

        /**
         * 设置上传状态
         *
         * @param uploadStatus
         * @return
         */
        public Builder setUploadStatus(int uploadStatus) {
            this.uploadStatus = uploadStatus;
            return this;
        }

        /**
         * 第几块
         *
         * @param chunck
         * @return
         */
        public Builder setChunck(int chunck) {
            this.chunck = chunck;
            return this;
        }

        /**
         * 设置文件名
         *
         * @param fileName
         * @return
         */
        public Builder setFileName(String fileName) {
            this.fileName = fileName;
            return this;
        }

        /**
         * 设置上传回调
         *
         * @param listener
         * @return
         */
        public Builder setListener(UploadTaskListener listener) {
            this.listener = listener;
            return this;
        }

        public UploadTask build() {
            return new UploadTask(this);
        }
    }

    private void addParams(MultipartBody.Builder builder, Map<String, String> params) {
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + key + "\""),
                        RequestBody.create(null, params.get(key)));
            }
        }
    }

}
UploadManager上传管理器
package com.mainaer.wjoklib.okhttp.upload;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;

/**
 * 上传管理器
 *
 * @author wangjian
 * @date 2016/5/13 .
 */
public class UploadManager {

    private static Context mContext;

    private static SQLiteDatabase db;
    private OkHttpClient mClient;

    private int mPoolSize = 20;
    // 将执行结果保存在future变量中
    private Map<String, Future> mFutureMap;
    private ExecutorService mExecutor;
    private Map<String, UploadTask> mCurrentTaskList;

    static UploadManager manager;

    /**
     * 方法加锁,防止多线程操作时出现多个实例
     */
    private static synchronized void init() {
        if (manager == null) {
            manager = new UploadManager();
        }
    }

    /**
     * 获得当前对象实例
     *
     * @return 当前实例对象
     */
    public final static UploadManager getInstance() {
        if (manager == null) {
            init();
        }
        return manager;
    }

    /**
     * 管理器初始化,建议在application中调用
     *
     * @param context
     */
    public static void init(Context context, SQLiteDatabase db1) {
        mContext = context;
        db = db1;
        getInstance();
    }

    public UploadManager() {
        initOkhttpClient();

        // 初始化线程池
        mExecutor = Executors.newFixedThreadPool(mPoolSize);
        mFutureMap = new HashMap<>();
        mCurrentTaskList = new HashMap<>();
    }

    /**
     * 初始化okhttp
     */
    private void initOkhttpClient() {
        OkHttpClient.Builder okBuilder = new OkHttpClient.Builder();
        okBuilder.connectTimeout(1000, TimeUnit.SECONDS);
        okBuilder.readTimeout(1000, TimeUnit.SECONDS);
        okBuilder.writeTimeout(1000, TimeUnit.SECONDS);
        mClient = okBuilder.build();
    }

    /**
     * 添加上传任务
     *
     * @param uploadTask
     */
    public void addUploadTask(UploadTask uploadTask) {
        if (uploadTask != null && !isUploading(uploadTask)) {
            uploadTask.setClient(mClient);
            uploadTask.setUploadStatus(UploadStatus.UPLOAD_STATUS_INIT);
            // 保存上传task列表
            mCurrentTaskList.put(uploadTask.getId(), uploadTask);
            Future future = mExecutor.submit(uploadTask);
            mFutureMap.put(uploadTask.getId(), future);
        }
    }

    private boolean isUploading(UploadTask task) {
        if (task != null) {
            if (task.getUploadStatus() == UploadStatus.UPLOAD_STATUS_UPLOADING) {
                return true;
            }
        }
        return false;
    }

    /**
     * 暂停上传任务
     *
     * @param id 任务id
     */
    public void pause(String id) {
        UploadTask task = getUploadTask(id);
        if (task != null) {
            task.setUploadStatus(UploadStatus.UPLOAD_STATUS_PAUSE);
        }
    }

    /**
     * 重新开始已经暂停的上传任务
     *
     * @param id 任务id
     */
    public void resume(String id, UploadTaskListener listener) {
        UploadTask task = getUploadTask(id);
        if (task != null) {
            addUploadTask(task);
        }
    }

/*    *//**
     * 取消上传任务(同时会删除已经上传的文件,和清空数据库缓存)
     *
     * @param id       任务id
     * @param listener
     *//*
    public void cancel(String id, UploadTaskListener listener) {
        UploadTask task = getUploadTask(id);
        if (task != null) {
            mCurrentTaskList.remove(id);
            mFutureMap.remove(id);
            task.setmListener(listener);
            task.cancel();
            task.setDownloadStatus(UploadStatus.DOWNLOAD_STATUS_CANCEL);
        }
    }*/

    /**
     * 实时更新manager中的task信息
     *
     * @param task
     */
    public void updateUploadTask(UploadTask task) {
        if (task != null) {
            UploadTask currTask = getUploadTask(task.getId());
            if (currTask != null) {
                mCurrentTaskList.put(task.getId(), task);
            }
        }
    }

    /**
     * 获得指定的task
     *
     * @param id task id
     * @return
     */
    public UploadTask getUploadTask(String id) {
        UploadTask currTask = mCurrentTaskList.get(id);
        if (currTask == null) {
                currTask = parseEntity2Task(new UploadTask.Builder().build());
                // 放入task list中
                mCurrentTaskList.put(id, currTask);
        }

        return currTask;
    }

    private UploadTask parseEntity2Task(UploadTask currTask) {

        UploadTask.Builder builder = new UploadTask.Builder()//
                .setUploadStatus(currTask.getUploadStatus())
                .setFileName(currTask.getFileName())//
                .setUrl(currTask.getUrl())
                .setId(currTask.getId());

            currTask.setBuilder(builder);

        return currTask;
    }
} 
FileUtils文件分块类


package com.mainaer.wjoklib.okhttp.upload;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class FileUtils {

    public static byte[] getBlock(long offset, File file, int blockSize) {
        byte[] result = new byte[blockSize];
        RandomAccessFile accessFile = null;
        try {
            accessFile = new RandomAccessFile(file, "r");
            accessFile.seek(offset);
            int readSize = accessFile.read(result);
            if (readSize == -1) {
                return null;
            } else if (readSize == blockSize) {
                return result;
            } else {
                byte[] tmpByte = new byte[readSize];
                System.arraycopy(result, 0, tmpByte, 0, readSize);
                return tmpByte;
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (accessFile != null) {
                try {
                    accessFile.close();
                } catch (IOException e1) {
                }
            }
        }
        return null;
    }

}

UploadTaskListener 接口类 
package com.mainaer.wjoklib.okhttp.upload;

import com.mainaer.wjoklib.okhttp.download.DownloadStatus;

import java.io.File;

/**
 * Created by hst on 16/9/21.
 */
public interface UploadTaskListener {
    /**
     * 上传中
     *
     * @param percent
     * @param uploadTask
     */
    void onUploading(UploadTask uploadTask, String percent,int position)

    /**
     * 上传成功
     *
     * @param file
     * @param uploadTask
     */
    void onUploadSuccess(UploadTask uploadTask, File file);

    /**
     * 上传失败
     *
     * @param uploadTask
     * @param errorCode    {@link DownloadStatus}
     */
    void onError(UploadTask uploadTask, int errorCode,int position);   

    /**
    * 上传暂停
    *
    * @param uploadTask
   *
   */
   void onPause(UploadTask uploadTask);
 }
android源码地址:https://github.com/handsometong/okhttpUpLoader
				
时间: 2024-10-29 10:45:49

okhttp实现断点上传的相关文章

实现TCP断点上传,后台C#服务实现接收

实现TCP断点上传,后台C#服务实现接收 终端实现大文件上传一直都是比较难的技术,其中涉及到后端与前端的交互,稳定性和流量大小,而且实现原理每个人都有自己的想法,后端主流用的比较多的是Http来实现,因为大多实现过断点下载.但稳定性不能保证,一旦断开,无法续传.所以得采用另一种流行的做法,TCP上传大文件. 网上查找了一些资料,大多数是断点下载,然后就是单独的C#端的上传接收,或是HTTP的,或是只有android端的,由于任务紧所以之前找的首选方案当然是Http先来实现文件上传,终端采用Pos

Android 文件断点上传器[多用户并发访问]

通过TCP/IP(SOCKET)协议实现文件断点上传(实现多用户并发访问). HTTP不支持文件断点续传,所以无法使用HTTP协议. 场景: 1. 网络不稳定,导致上传失败,下次不是从头开始,而是从断点开始上传: 2. 上传大文件,无法http上传,因为web服务器考虑到安全因素,会限制文件大小,一般10+m. 此文件断点上传器使用自定义协议. 服务器为上传的文件在服务器端生成唯一的sourceid关联上传文件,当客户端上传文件时,首次的sourceid为空,服务端先判断sourceid是否为空

文件断点上传,html5实现前端,java实现服务器

断点上传能够防止意外情况导致上传一半的文件下次上传时还要从头下载,网上有很多关于断点的实现,这篇文章只是从前到后完整的记录下一个可用的实例,由于生产环境要求不高,而且就是提供给一两个人用,所以我简化了诸多过程,不用flash,也不用applet,只是通过html5的新特性进行浏览器端的处理. 简单说下关键点 如果上次传到n字节,那么浏览器下次续传直接就是从文件的n字节开始向服务器传送数据,而不是都传过去,服务器从n字节开始接收. html5能给文件分片,所以每次上传完一块文件后,应该返回当前已经

Android中Socket大文件断点上传

什么是Socket? 所谓Socket通常也称作“套接字”,用于描述IP地址和端口,是一个通信连的句柄,应用程序通常通过“套接字”向网络发送请求或者应答网络请求,它就是网络通信过程中端点的抽象表示.它主要包括以下两个协议: TCP (Transmission Control Protocol 传输控制协议):传输控制协议,提供的是面向连接.可靠的字节流服务.当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据.TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功

netty4 实现一个断点上传大文件功能

我本来以为文件断点续传功能很简单,不就是提供2个方法: 一个返回已经上传的文件的长度:另外一个负责上传文件呗(请求带上content-range 指明本次上传的内容在整个文件中的位置),然后根据请求提供的位置写呗,太简单了. 但是实际情况还是比较复杂的,关键问题是,上面的描述现在想想只能称作为文件分段上传,而不是断点续传. 断点意味着网络会断,然后断了之后,服务端根本获取不到本次上传的内容,于是下次又只能从头开始传文件.一种解决办法是客户端将文件分成很小的片段(单个片段丢了就整个片段重传),这个

Android应用开发之使用Socket进行大文件断点上传续传

http://www.linuxidc.com/Linux/2012-03/55567.htm http://blog.csdn.net/shimiso/article/details/8529633/ 在Android中上传文件可以采用HTTP方式,也可以采用Socket方式,但是HTTP方式不能上传大文件,这里介绍一种通过Socket方式来进行断点续传的方式,服务端会记录下文件的上传进度,当某一次上传过程意外终止后,下一次可以继续上传,这里用到的其实还是J2SE里的知识. 这个上传程序的原理

WebApi 文件上传,断点上传,分块上传,断点下载,查询 (图片的直接预览,视频边加载边播放)

using Manjinba.Communication.Common.Caching;using Manjinba.Communication.Common.Logging;using Manjinba.Communication.Common.Utils;using Manjinba.Communication.IRepository;using Manjinba.Communication.IService;using Manjinba.Communication.Model;using

[转]用C#如何实现大文件的断点上传

最近做在做一个项目,涉及到文件上传的问题. 以前也做过文件上传.但都是些小文件,不超过2m. 这次要求上传1g以上的东西. 没办法找来资料研究了一下. 基于web的文件上传可以使用ftp和http两种协议,用ftp的话虽然传输稳定,但安全性是个严重的问题,所以没有考虑. 剩下只有http. 在http中有3种方式,put.webdav.rfc1867,前2种方法不适合大文件上传,在这里也不说了. 确定使用rfc1867格式处理之后开始分析流行的上传组件.看了n多代码之后发现,目前无组件程序和一些

asp.net文件断点上传

HTML部分 <%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="index.aspx.cs"Inherits="up6.index" %> <!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.0 Transitional//EN""http://www.w3.org/TR/xhtml1/DTD/