断点续传_断点续传源码 - CSDN
精华内容
参与话题
  • 文件断点续传原理与实现

    千次阅读 2014-12-06 22:38:21
    在网络状况不好的情况下,对于文件的传输,我们希望能够支持可以每次传部分数据。首先从文件传输协议FTP和TFTP开始分析, ...本次以IM中的文件下载场景为例,解析基于TCP的文件断点续传的原理,并用代码实现。

    在网络状况不好的情况下,对于文件的传输,我们希望能够支持可以每次传部分数据。首先从文件传输协议FTP和TFTP开始分析,

    FTP是基于TCP的,一般情况下建立两个连接,一个负责指令,一个负责数据;而TFTP是基于UDP的,由于UDP传输是不可靠的,虽然传输速度很快,但对于普通的文件像PDF这种,少了一个字节都不行。本次以IM中的文件下载场景为例,解析基于TCP的文件断点续传的原理,并用代码实现。

    什么是断点续传?

    断点续传其实正如字面意思,就是在下载的断开点继续开始传输,不用再从头开始。所以理解断点续传的核心后,发现其实和很简单,关键就在于对传输中断点的把握,我就自己的理解画了一个简单的示意图:

    原理:

    断点续传的关键是断点,所以在制定传输协议的时候要设计好,如上图,我自定义了一个交互协议,每次下载请求都会带上下载的起始点,这样就可以支持从断点下载了,其实HTTP里的断点续传也是这个原理,在HTTP的头里有个可选的字段RANGE,表示下载的范围,下面是我用JAVA语言实现的下载断点续传示例。

    提供下载的服务端代码:

    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.RandomAccessFile;
    import java.io.StringWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    // 断点续传服务端
    public class FTPServer {
    
    	// 文件发送线程
    	class Sender extends Thread{
    		// 网络输入流
    		private InputStream in;
    		// 网络输出流
    		private OutputStream out;
    		// 下载文件名
    		private String filename;
    
    		public Sender(String filename, Socket socket){
    			try {
    				this.out = socket.getOutputStream();
    				this.in = socket.getInputStream();
    				this.filename = filename;
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		
    		@Override
    		public void run() {
    			try {
    				System.out.println("start to download file!");
    				int temp = 0;
    				StringWriter sw = new StringWriter();
    				while((temp = in.read()) != 0){
    					sw.write(temp);
    					//sw.flush();
    				}
    				// 获取命令
    				String cmds = sw.toString();
    				System.out.println("cmd : " + cmds);
    				if("get".equals(cmds)){
    					// 初始化文件
    					File file = new File(this.filename);
    					RandomAccessFile access = new RandomAccessFile(file,"r");
    					//
    					StringWriter sw1 = new StringWriter();
    					while((temp = in.read()) != 0){
    						sw1.write(temp);
    						sw1.flush();
    					}
    					System.out.println(sw1.toString());
    					// 获取断点位置
    					int startIndex = 0;
    					if(!sw1.toString().isEmpty()){
    						startIndex = Integer.parseInt(sw1.toString());
    					}
    					long length = file.length();
    					byte[] filelength = String.valueOf(length).getBytes();
    					out.write(filelength);
    					out.write(0);
    					out.flush();
    					// 计划要读的文件长度
    					//int length = (int) file.length();//Integer.parseInt(sw2.toString());
    					System.out.println("file length : " + length);
    					// 缓冲区10KB
    					byte[] buffer = new byte[1024*10];
    					// 剩余要读取的长度
    					int tatol = (int) length;
    					System.out.println("startIndex : " + startIndex);
    					access.skipBytes(startIndex);
    					while (true) {
    						// 如果剩余长度为0则结束
    						if(tatol == 0){
    							break;
    						}
    						// 本次要读取的长度假设为剩余长度
    						int len = tatol - startIndex;
    						// 如果本次要读取的长度大于缓冲区的容量
    						if(len > buffer.length){
    							// 修改本次要读取的长度为缓冲区的容量
    							len = buffer.length;
    						}
    						// 读取文件,返回真正读取的长度
    						int rlength = access.read(buffer,0,len);
    						// 将剩余要读取的长度减去本次已经读取的
    						tatol -= rlength;
    						// 如果本次读取个数不为0则写入输出流,否则结束
    						if(rlength > 0){
    							// 将本次读取的写入输出流中
    							out.write(buffer,0,rlength);
    							out.flush();
    						} else {
    							break;
    						}
    						// 输出读取进度
    						//System.out.println("finish : " + ((float)(length -tatol) / length) *100 + " %");
    					}
    					//System.out.println("receive file finished!");
    					// 关闭流
    					out.close();
    					in.close();
    					access.close();
    				}
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    			super.run();
    		}
    	}
    	
    	public void run(String filename, Socket socket){
    		// 启动接收文件线程 
    		new Sender(filename,socket).start();
    	}
    	
    	public static void main(String[] args) throws Exception {
    		// 创建服务器监听
    		ServerSocket server = new ServerSocket(8888);
    		// 接收文件的保存路径
    		String filename = "E:\\ceshi\\mm.pdf";
    		for(;;){
    			Socket socket = server.accept();
    			new FTPServer().run(filename, socket);
    		}
    	}
    
    }

    下载的客户端代码:

    import java.io.File;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.RandomAccessFile;
    import java.io.StringWriter;
    import java.net.InetSocketAddress;
    import java.net.Socket;
    
    // 断点续传客户端
    public class FTPClient {
    
    	/**
    	 *  request:get0startIndex0
    	 *  response:fileLength0fileBinaryStream
    	 *  
    	 * @param filepath
    	 * @throws Exception
    	 */
    	public void Get(String filepath) throws Exception {
    		Socket socket = new Socket();
    		// 建立连接
    		socket.connect(new InetSocketAddress("127.0.0.1", 8888));
    		// 获取网络流
    		OutputStream out = socket.getOutputStream();
    		InputStream in = socket.getInputStream();
    		// 文件传输协定命令
    		byte[] cmd = "get".getBytes();
    		out.write(cmd);
    		out.write(0);// 分隔符
    		int startIndex = 0;
    		// 要发送的文件
    		File file = new File(filepath);
    		if(file.exists()){
    			startIndex = (int) file.length();
    		}
    		System.out.println("Client startIndex : " + startIndex);
    		// 文件写出流
    		RandomAccessFile access = new RandomAccessFile(file,"rw");
    		// 断点
    		out.write(String.valueOf(startIndex).getBytes());
    		out.write(0);
    		out.flush();
    		// 文件长度
    		int temp = 0;
    		StringWriter sw = new StringWriter();
    		while((temp = in.read()) != 0){
    			sw.write(temp);
    			sw.flush();
    		}
    		int length = Integer.parseInt(sw.toString());
    		System.out.println("Client fileLength : " + length);
    		// 二进制文件缓冲区
    		byte[] buffer = new byte[1024*10];
    		// 剩余要读取的长度
    		int tatol = length - startIndex;
    		//
    		access.skipBytes(startIndex);
    		while (true) {
    			// 如果剩余长度为0则结束
    			if (tatol == 0) {
    				break;
    			}
    			// 本次要读取的长度假设为剩余长度
    			int len = tatol;
    			// 如果本次要读取的长度大于缓冲区的容量
    			if (len > buffer.length) {
    				// 修改本次要读取的长度为缓冲区的容量
    				len = buffer.length;
    			}
    			// 读取文件,返回真正读取的长度
    			int rlength = in.read(buffer, 0, len);
    			// 将剩余要读取的长度减去本次已经读取的
    			tatol -= rlength;
    			// 如果本次读取个数不为0则写入输出流,否则结束
    			if (rlength > 0) {
    				// 将本次读取的写入输出流中
    				access.write(buffer, 0, rlength);
    			} else {
    				break;
    			}
    			System.out.println("finish : " + ((float)(length -tatol) / length) *100 + " %");
    		}
    		System.out.println("finished!");
    		// 关闭流
    		access.close();
    		out.close();
    		in.close();
    	}
    
    	public static void main(String[] args) {
    		FTPClient client = new FTPClient();
    		try {
    			client.Get("E:\\ceshi\\test\\mm.pdf");
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    测试
    原文件、下载中途断开的文件和从断点下载后的文件分别从左至右如下:


    断点前的传输进度如下(中途省略):

    Client fileLength : 51086228
    finish : 0.020044541 %
    finish : 0.040089082 %
    finish : 0.060133625 %
    finish : 0.07430574 %
    finish : 0.080178164 %
    ...
    finish : 60.41171 %
    finish : 60.421593 %
    finish : 60.428936 %
    finish : 60.448982 %
    finish : 60.454338 %

    断开的点计算:30883840 / 51086228 = 0.604543361471119 * 100% = 60.45433614%

    从断点后开始传的进度(中途省略):
    Client startIndex : 30883840
    Client fileLength : 51086228
    finish : 60.474377 %
    finish : 60.494423 %
    finish : 60.51447 %
    finish : 60.53451 %
    finish : 60.554558 %
    ...
    finish : 99.922035 %
    finish : 99.942085 %
    finish : 99.95677 %
    finish : 99.96213 %
    finish : 99.98217 %
    finish : 100.0 %
    finished!

    断点处前后的百分比计算如下:

    ============================下面是从断点开始的进度==============================

    本方案是基于TCP,在本方案设计之初,我还探索了一下介于TCP与UDP之间的一个协议:UDT(基于UDP的可靠传输协议)。

    我基于Netty写了相关的测试代码,用Wireshark拆包发现的确是UDP的包,而且是要建立连接的,与UDP不同的是需要建立连接,所说UDT的传输性能比TCP好,传输的可靠性比UDP好,属于两者的一个平衡的选择,感兴的可以深入研究一下。

    展开全文
  • 断点续传实现

    千次阅读 2019-06-24 18:25:15
    断点续传实现: 简单来说应该分为两个角度来看待: 1、将要续传的文件 2、续传的文件 一、将要续传的文件 先说说将要续传的文件,既然是续传,那么肯定要有个标识,举例说明一下: 事先准备一个文件,大小是1852...

    断点续传实现:

    简单来说应该分为两个角度来看待:

    1、将要续传的文件

    2、续传的文件

    一、将要续传的文件

    先说说将要续传的文件,既然是续传,那么肯定要有个标识,举例说明一下:

        事先准备一个文件,大小是1852字节,第一次读取该文件的io流(0-1024字节),并将1024作为下次读取的首值,存储1024这个变量,就是在这个过程中的标识(记录所读到的位置) ,通过这个标识,我们下次读取的字节范围应该就是(1024-1852)字节。

       要完成这个需求,应该考虑二个角度,

       1)、这个标识放在那里,(我之后举得列子是放在持久化map[ConcurrentHashMap])

       2)、既然是续传,那么肯定需要一个结束的状态的标识,来告诉续传的文件,我已经执行完了。

       下面是关键代码:

        (1),ConcurrentHashMap

         ConcurrentHashMap的优点:

        ConcurrentHashMap允许一边更新、一边遍历,也就是说在Iterator对象遍历的时候,

        ConcurrentHashMap也可以进行remove,put操作,且遍历的数据会随着remove,put操作产出变化,也就是说在Iterator对象遍历的时候,ConcurrentHashMap也可以进行remove,put操作,且遍历的数据会随着remove,put操作产出变化。

        简单来说:它只对put,remove操作使用了同步操作,get操作并不影响

        代码如下:

    package ga.gaapi.config;
    
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class ZjHashMap {
        static Map<String,Long> conMap = new ConcurrentHashMap<>();
        //新增
        public static void addMap(String key,Long value){
            conMap.put(key,value);
        }
        //删除
        public  static void delect(String key){
            conMap.remove(key);
        }
    
        //获取
        public static  Long get(String key){
            return  conMap.get(key);
        }
    
    }
    

    (2)、读取文件部分核心代码:

    path :路径,

    fileName:文件名。

    try{    
    
        File file = new File(path+"\\"+fileName);
        RandomAccessFile raf = new RandomAccessFile(file,"r");
        long count = file.length();
        byte[] read = new byte[Integer.parseInt(size)];
        int len =0;
        long fy = 0;
        long flag = 1;
    
         //判断标识中是否有值,有值的话,作为读取的首值
         if (null!= ZjHashMap.get(fileName)){
            raf.seek(ZjHashMap.get(fileName));
            //计算要分页的数量,用来判断是否已经全部读取
            fy = PostUtils.fy(count-ZjHashMap.get(fileName), Long.parseLong(size));
         }else{
            //计算要分页的数量,用来判断是否已经全部读取
            fy = PostUtils.fy(count, Long.parseLong(size));
         }
              while((len=raf.read(read))!=-1){
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                outputStream.write(read,0,len);
                outputStream.flush();
                //读取的字节
                byte[] bytes = outputStream.toByteArray();
    
                //把字节数发送给续传文件方
    
                //当前字节数目
                ZjHashMap.addMap(fileName,raf.getFilePointer());
                  if (flag == fy){
                     //表示已到结尾,可以将这部分逻辑发送给续传文件方,告诉它已续传完毕
                  }
                flag ++;
                outputStream.close();
             }
         raf.close();
         ZjHashMap.delect(fileName);
    
    }catch (Exception e){
    
               
    }
    

    、续传的文件

    续传的文件就好说了,只要给一个续传的标识位置,和对应的字节流就可以了,代码如下:

    filePath:生成的文件,用来续传用

    content:将要写入的字节

    position:续传的字节位置

     RandomAccessFile raf = null;
            try {
                raf = new RandomAccessFile(filePath, "rw"); //将随机存取文件流连接到文件,访问方式设置为可读可写
                raf.seek(position); //指定插入的位置
                raf.write(content); //插入指定内容
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                //关闭随机存取文件流
                try {
                    raf.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

     

    展开全文
  • 大文件断点续传功能

    2020-07-29 14:18:22
    找了很久的断点续传功能。之前也试过百度的webuploader,但是效果并不理想(想研究的也可以试试),然后一直找,找了很久,直到找到这个后,才基本满足功能所需,可以实现大文件断点续传的需求。大文件断点续传的...
  • 浅谈HTTP断点续传原理

    万次阅读 2018-09-18 10:52:11
    断点续传就是从文件上次中断的地方开始重新下载或上传,当下载或上传文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会去重头下载,这样很浪费时间。所以断点续传的功能就应运而生了。要...

    断点续传就是从文件上次中断的地方开始重新下载或上传,当下载或上传文件的时候,如果没有实现断点续传功能,那么每次出现异常或者用户主动的暂停,都会去重头下载,这样很浪费时间。所以断点续传的功能就应运而生了。要实现断点续传的功能,需要客户端记录下当前的下载或上传进度,并在需要续传的时候通知服务端本次需要下载或上传的内容片段。

    下面来简单介绍 HTTP 断点续传的原理:

    其实断点续传的原理很简单,就是在Http的请求上多定义了断点续传相关的HTTP头 Range和Content-Range字段而已,例如!

    1.浏览器请求服务器上的一个文件名为test.zip时,请求内容只展示了一些与本文有关的信息

    GET /test.zip HTTP/1.1Accept-Language: zh-cnAccept-Encoding: gzip, deflateConnection: Keep-Alive

    2.服务器收到请求后,按要求寻找请求的文件,提取文件的信息,然后返回给浏览器,返回信息如下:

    200Content-Length=66667777Accept-Ranges=bytesContent-Type=application/octet-stream

    为了实现从文件已经下载的地方开始继续下载。所以在客户端传给服务器的时候要多加一条信息--从哪里开始。下面是客户端请求时的请求信息,要求从44445555字节开始。

    GET /test.zip HTTP/1.0User-Agent: NetFoxRANGE: bytes=44445555-

    上面的请求信息多了一个新的字段RANGE RANGE:bytes=44445555-
    这段话的意思就是告诉服务器test.zip这个文件从44445555字节开始传,前面的字节不用传了。服务器收到这个请求以后,返回的信息如下:

    206Content-Length=66667777Content-Range=bytes 44445555-66667777Content-Type=application/octet-stream

    和第一次服务器返回的信息相比,增加了一行:
    Content-Range=bytes 44445555-66667777
    返回的代码也改为206了,而不再是200了。

    但是在实际场景中,会出现一种情况,即在终端发起续传请求时,URL对应的文件内容在服务端已经发生变化,此时续传的数据肯定是错误的。如何解决这个问题了?显然此时我们需要有一个标识文件唯一性的方法。在RFC2616中也有相应的定义,比如实现Last-Modified来标识文件的最后修改时间,这样即可判断出续传文件时是否已经发生过改动。同时RFC2616中还定义有一个ETag的头,可以使用ETag头来放置文件的唯一标识,比如文件的MD5值。

    终端在发起续传请求时应该在HTTP头中申明If-Match 或者If-Modified-Since 字段,帮助服务端判别文件变化。 

    另外RFC2616中同时定义有一个If-Range头,终端如果在续传是使用If-Range。If-Range中的内容可以为最初收到的ETag头或者是Last-Modfied中的最后修改时候。服务端在收到续传请求时,通过If-Range中的内容进行校验,校验一致时返回206的续传回应,不一致时服务端则返回200回应,回应的内容为新的文件的全部数据。

    展开全文
  • 断点续传

    2019-06-27 21:36:32
    今天敲了一个断点续传 说的直白一点,其实就是在读取循环中设卡,并且在继续的时候能拿到之前暂停时的位置,并用自由文件流进行seek,就可以继续了,清楚了原理就可以直接动手了哦 布局 <ProgressBar android:...

    今天敲了一个断点续传

    说的直白一点,其实就是在读取循环中设卡,并且在继续的时候能拿到之前暂停时的位置,并用自由文件流进行seek,就可以继续了,清楚了原理就可以直接动手了哦

    布局

     <ProgressBar
            android:layout_above="@id/ll"
            android:id="@+id/prb"
            style="@style/Widget.AppCompat.ProgressBar.Horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
        <LinearLayout
            android:id="@+id/ll"
            android:orientation="vertical"
            android:layout_centerInParent="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
    
            <TextView
                android:id="@+id/text123456"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
            <Button
                android:text="开始"
                android:id="@+id/btn"
                android:layout_centerInParent="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
    
            <Button
                android:layout_alignParentBottom="true"
                android:text="暂停"
                android:id="@+id/btn1"
                android:layout_centerHorizontal="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
    

    活动代码

    public class MainActivity extends AppCompatActivity {
    
        TextView textView;
        int sum = 0;
        boolean flag = true;
        ProgressBar progressBar
        int max;
        int time = 0;
        long start = 0;
        long end = 1024 * 1024;
        Handler handler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if (msg.what == 100 && msg.obj != null&&flag==true) {
                    if (time < 5) {
                        new DownloadThread().start();
                        time++;
                        Log.d("####", msg.obj.toString());
                    } else {
                        handler.sendEmptyMessage(1);
                        Log.d("####", msg.obj.toString());
                    }
                } else if (msg.what == 1) {
    
                }else if(msg.what==200){
                    textView.setText(msg.obj.toString());
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            textView=findViewById(R.id.text123456);
            progressBar = findViewById(R.id.prb);
            Button button = findViewById(R.id.btn);
            Button button1 = findViewById(R.id.btn1);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    flag = true;
                    start=sum;
                    new DownloadThread().start();
                }
            });
            button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
    
                    flag = false;
                }
            });
        }
    
        class DownloadThread extends Thread {
            @Override
            public void run() {
                super.run();
                try {
                    URL url = new URL("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
                    URL url1 = new URL("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
                    HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
                    HttpURLConnection httpURLConnection1 = (HttpURLConnection) url1.openConnection();
                    int contentLength = httpURLConnection1.getContentLength();
                    progressBar.setMax(contentLength);
                    httpURLConnection.setRequestMethod("GET");
                    httpURLConnection.setDoInput(true);
                    httpURLConnection.setDoOutput(true);
    
                    String path = Environment.getExternalStorageDirectory().getPath() + "/test.mp4";
                    RandomAccessFile randomAccessFile = new RandomAccessFile(path, "rw");
                    randomAccessFile.seek(start);
                    httpURLConnection.setRequestProperty("Range", "bytes=" + start + "-" + end);
    
                    if (httpURLConnection.getResponseCode() == 206) {
    
                        max = httpURLConnection.getContentLength();
    
    //                    总长度 range bytes=0-1024*1024
                        InputStream inputStream = httpURLConnection.getInputStream();
                        byte b[] = new byte[1024];
                        int len = 0;
                        while ((len = inputStream.read(b)) != -1) {
                            randomAccessFile.write(b, 0, len);
                            sum += len;
                            progressBar.setProgress(sum);
                            if (flag == false) {
                                break;
                            }
                            String s = sum * 100 / progressBar.getMax() + "%";
                            Message message = Message.obtain();
                            message.what = 200;
                            message.obj = s;
                            handler.sendMessage(message);
                        }
                        //从上次结束的位置+1开始读
                        start = end + 1;
                        end += 1024 * 1024;
                        Message message = Message.obtain();
                        message.what = 100;
                        String str = "文件" + time + "下载成功:" + start + "-" + end;
    
                        Log.d("###", "run: " + str);
                        message.obj = str;
                        handler.sendMessage(message);
                    }
    
                
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    

    INTERESTING!!!

    展开全文
  • 断点续传工具

    2020-07-28 23:31:06
    非常好用的断点续传工具,可以实现远程传输文件
  • 前面讲了文件的上传,今天来聊聊文件的下载。...在贴代码之前先来了解下什么是断点续传(这里说的是下载断点续传)?怎么实现的断点续传断点续传就是下载了一半断网或者暂停了,然后可以接着下载。不用从头开始下
  • java两台服务器之间,大文件上传(续传),采用了Socket通信机制,具体思路如下:实现思路: 1、服:利用ServerSocket搭建服务器,开启相应端口,进行长连接操作 2、服:使用ServerSocket.accept()方法进行...
  • Android开发——断点续传原理以及实现

    万次阅读 多人点赞 2018-04-07 14:22:34
    0. 前言在Android开发中,断点续传听起来挺容易,在下载一个文件... 断点续传原理在本地下载过程中要使用数据库实时存储到底存储到文件的哪个位置了,这样点击开始继续传递时,才能通过HTTP的GET请求中的setReque...
  • HTTP断点续传上传控件

    热门讨论 2020-07-30 23:32:42
    对于开发人员来说,有了这些信息,断点续传功能将会变的和普通的文件上传功能一样简单。 相信新颖网络HTTP断点续传控件能够帮助您赢利市场。 版权所有 2009-2012 北京新颖网络 保留所有权利 官方网站:...
  • fastDFS断点续传实例

    2020-07-30 23:32:07
    fastDFS断点续传的一个小Demo,用maven构建的项目。之前在网上找了好久关于断点续传的实例,没有找到,特意分享出来了。
  • Qt5 QFtp普通文件断点续传

    热门讨论 2020-07-30 23:33:25
    1 自动文件上传(断点续传) 需要在上传文件之前调用QFtp下的list 通过listInfor 信号 获取当前要上传的文件是否存在 如果存在 比较大小 或者通过计算MD5值 比较文件的完整性 然后确定是否需要断点续传 或者覆盖 ...
  • 本人先前的博客有对多文件分段断点续传的功能进行详细的介绍,如果你有兴趣可以先阅读Android多文件断点续传(一)——数据封装以及界面实现。本人在先前的基础上对代码进行了封装,本帖主要介绍如何集成封装好的...
  • C# FTP上传下载(支持断点续传

    万次阅读 热门讨论 2019-04-22 15:50:34
    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Net; using System.IO; namespace JianKunKing.Common.Ftp { /// <summary> /// ftp方式文件下载...
  • nginx断点续传

    万次阅读 2017-06-23 00:32:24
    这其实是nginx的断点续传功能, 从指定位置开始观看,相当于向nginx服务器请求某个位置开始的以后的内容。假设nginx服务器上有一个文件,文件的内容为: "0123456789abcdef"一共16个字节。如果客户端只需要2345共4个...
  • C++ 断点续传

    热门讨论 2020-07-19 23:31:38
    服务端和客户端,C++ socket 编程实现,支持断点续传,可供参考学习用。
  • ftp 断点续传实现

    2020-07-30 23:33:30
    ftp实现断点续传,ftp支持上传续传 ftp断点续传基于c语言的实现。
  • OKHttp断点续传Demo 下载

    热门讨论 2020-07-29 14:18:31
    Andriod平台 基于OKHttp3 封装的,配合RxJava使用的 断点续传功能代码,配合博客使用
  • Java断点续传实现原理很简单

    万次阅读 多人点赞 2016-07-16 12:59:13
    原理解析在开发当中,“断点续传”这种功能很实用和常见,听上去也是比较有“逼格”的感觉。所以通常我们都有兴趣去研究研究这种功能是如何实现的? 以Java来说,网络上也能找到不少关于实现类似功能的资料。但是呢...
  • 断点续传的原理

    千次阅读 2016-07-01 17:54:48
    断点续传是大型文件数据传输的核心。本文将以多线程技术和Socket技术为依托,介绍大型文件断点续传的实现方法。  基本实现思想  多线程断点续传实现的基本思想就是在发送端(也称客户端)将要传输的文件分割...
1 2 3 4 5 ... 20
收藏数 40,698
精华内容 16,279
关键字:

断点续传