断点续传

断点续传

什么是断点续传?

断点续传其实正如字面意思,就是在上传或下载的断开点继续开始传输,不用再从头开始。

断点的由来是在下载过程中,将一个下载文件分成了多个部分,同时进行多个部分一起的下载,当某个时间点,任务被暂停了,此时下载暂停的位置就是断点了。

续传就是当一个未完成的下载任务再次开始时,会从上次的断点继续传送。

这样的功能如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载以后未上传下载的部分,而没有必要重头开始上传下载。可以节省时间,提高速度。

实现过程

1.传输开始之前发送方先向接收方发送一个确认信息,然后再向接收方发送准备发送的文件的文件名
2.接收方收到确认信息之后,接收从发送方发送过来的文件名,接收完之后向发送方发送一个确认信息表示文件名接收完毕,然后接收方根据收到的文件名创建一个“.temp”File对象和一个“.temp”RandomAccessFile对象。获取这个File对象所对应文件的长度(大小)(这个长度就是接收方已经接受的长度,如果之前没有接收过这个文件,长度就为0),并把文件长度发送给发送方。
3.发送方收到确认信息之后,接收接受方发送的文件长度,然后向接收方发送准备发送的文件的总长度,并向接收方发送一个确认信息。然后根据接收方发送的文件长度,从文件对应长度的位置开始发送。
4.接收方收到确认信息之后,接受发送方发送过来的数据,然后从此文件的末尾写入。接受完成之后再将“.temp”文件重命名为正常的文件名。

示意图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjPIQNfy-1604366610712)(C:\Users\Administrator\Desktop\断点续传\20180120013406658.jpg)]

“ok”表示确认信息.

实现代码

1.发送端

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.Socket;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;

public class SendFileThread extends Thread{

    private Socket socket=null;
    private DataOutputStream dos;
    private DataInputStream dis;
    private RandomAccessFile rad;
    private Container contentPanel;
    private JFrame frame;
    private JProgressBar progressbar;
    private JLabel label;

    public SendFileThread(){
        frame=new JFrame("文件传输");
        try {
            socket=new Socket("localhost", 8080);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void run(){

        JFileChooser fc = new JFileChooser();
        int status=fc.showOpenDialog(null);

        if (status==JFileChooser.APPROVE_OPTION) {
            String path=fc.getSelectedFile().getPath();
            try {

                dos=new DataOutputStream(socket.getOutputStream());
                dis=new DataInputStream(socket.getInputStream());
                dos.writeUTF("ok");

                rad=new RandomAccessFile(path, "r");
                File file=new File(path);

                byte[] buf=new byte[1024];
                dos.writeUTF(file.getName());
                dos.flush();
                String rsp=dis.readUTF();

                if (rsp.equals("ok")) {
                    long size=dis.readLong();//读取文件已发送的大小
                    dos.writeLong(rad.length());
                    dos.writeUTF("ok");
                    dos.flush();

                    long offset=size;//字节偏移量

                    int barSize=(int) (rad.length()/1024);
                    int barOffset=(int)(offset/1024);

2.发送端图形界面

//传输界面
frame.setSize(380,120);
contentPanel = frame.getContentPane();
contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
progressbar = new JProgressBar();//进度条

label=new JLabel(file.getName()+" 发送中");
contentPanel.add(label);

progressbar.setOrientation(JProgressBar.HORIZONTAL);
progressbar.setMinimum(0);
progressbar.setMaximum(barSize);
progressbar.setValue(barOffset);
progressbar.setStringPainted(true);
progressbar.setPreferredSize(new Dimension(150, 20));
progressbar.setBorderPainted(true);
progressbar.setBackground(Color.pink);

JButton cancel=new JButton("取消");

JPanel barPanel=new JPanel();
barPanel.setLayout(new FlowLayout(FlowLayout.LEFT));

barPanel.add(progressbar);
barPanel.add(cancel);

contentPanel.add(barPanel);

cancel.addActionListener(new cancelActionListener());

frame.setDefaultCloseOperation(
        JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
//从文件指定位置开始传输
                int length;
                if (offset<rad.length()) {
                    rad.seek(offset);
                    while((length=rad.read(buf))>0){
                        dos.write(buf,0,length);
                        progressbar.setValue(++barOffset);
                        dos.flush();
                    }
                }
                label.setText(file.getName()+" 发送完成");
            }

            dis.close();
            dos.close();
            rad.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            label.setText(" 取消发送,连接关闭");
        }finally {
            frame.dispose();
        }

    }
}
class cancelActionListener implements ActionListener{
    public void actionPerformed(ActionEvent e3){
        try {
            label.setText(" 取消发送,连接关闭");
            JOptionPane.showMessageDialog(frame, "取消发送给,连接关闭!", "提示:", JOptionPane.INFORMATION_MESSAGE);
            dis.close();
            dos.close();
            rad.close();
            frame.dispose();
            socket.close();
        } catch (IOException e1) {

        }
    }
}

启动写一个方法调用即可

public class FileSendTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        SendFileThread sf=new SendFileThread();
        sf.start();
    }
}

3.接收端代码

import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.ServerSocket;
import java.net.Socket;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;


public class ReceiveFileThread extends Thread{

    private ServerSocket connectSocket=null;
    private Socket socket=null;
    private JFrame frame;
    private Container contentPanel;
    private JProgressBar progressbar;
    private DataInputStream dis;
    private DataOutputStream dos;
    private RandomAccessFile rad;
    private JLabel label;

    public ReceiveFileThread(){
        frame=new JFrame("接收文件");
        try {
            connectSocket=new ServerSocket(8080);
            socket=connectSocket.accept();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public void run(){
        try {
            dis=new DataInputStream(socket.getInputStream());
            dos=new DataOutputStream(socket.getOutputStream());
            dis.readUTF();

            int permit=JOptionPane.showConfirmDialog(frame, "是否接收文件","文件传输请求:", JOptionPane.YES_NO_OPTION);
            if (permit==JOptionPane.YES_OPTION) {
                String filename=dis.readUTF();
                dos.writeUTF("ok");
                dos.flush();
                File file=new File(filename+".temp");
                rad=new RandomAccessFile(filename+".temp", "rw");

                //获得文件大小
                long size=0;
                if(file.exists()&&file.isFile()){
                    size=file.length();
                }

                dos.writeLong(size);//发送已接收的大小
                dos.flush();
                long allSize=dis.readLong();
                String rsp=dis.readUTF();

                int barSize=(int)(allSize/1024);
                int barOffset=(int)(size/1024);

                //传输界面
                frame.setSize(300,120);
                contentPanel =frame.getContentPane();
                contentPanel.setLayout(new BoxLayout(contentPanel, BoxLayout.Y_AXIS));
                progressbar = new JProgressBar();//进度条

                label=new JLabel(filename+" 接收中");
                contentPanel.add(label);

                progressbar.setOrientation(JProgressBar.HORIZONTAL);
                progressbar.setMinimum(0);
                progressbar.setMaximum(barSize);
                progressbar.setValue(barOffset);
                progressbar.setStringPainted(true);
                progressbar.setPreferredSize(new Dimension(150, 20));
                progressbar.setBorderPainted(true);
                progressbar.setBackground(Color.pink);

                JButton cancel=new JButton("取消");

                JPanel barPanel=new JPanel();
                barPanel.setLayout(new FlowLayout(FlowLayout.LEFT));

                barPanel.add(progressbar);
                barPanel.add(cancel);

                contentPanel.add(barPanel);

                cancel.addActionListener(new cancelActionListener());

                frame.setDefaultCloseOperation(
                        JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);

                //接收文件
                if (rsp.equals("ok")) {
                    rad.seek(size);
                    int length;
                    byte[] buf=new byte[1024];
                    while((length=dis.read(buf, 0, buf.length))!=-1){
                        rad.write(buf,0,length);
                        progressbar.setValue(++barOffset);
                    }
                    System.out.println("end");
                }

                label.setText(filename+" 结束接收");


                dis.close();
                dos.close();
                rad.close();
                frame.dispose();
                //文件重命名
                if (barOffset>=barSize) {
                    file.renameTo(new File(filename));
                }

            }else{
                dis.close();
                dos.close();
                frame.dispose();
            }

        } catch (IOException e) {
            // TODO Auto-generated catch block
            label.setText(" 已取消接收,连接关闭!");
        }finally {
            frame.dispose();
        }
    }

    class cancelActionListener implements ActionListener{
        public void actionPerformed(ActionEvent e){
            try {
                dis.close();
                dos.close();
                rad.close();
                JOptionPane.showMessageDialog(frame, "已取消接收,连接关闭!", "提示:", JOptionPane.INFORMATION_MESSAGE);
                label.setText(" 取消接收,连接关闭");
            } catch (IOException e1) {

            }
        }
    }

}

接收端启动调用方法

public class FileReceiveTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ReceiveFileThread rf=new ReceiveFileThread();
        rf.start();
    }
}

RMATION_MESSAGE);
label.setText(" 取消接收,连接关闭");
} catch (IOException e1) {

        }
    }
}

}


接收端启动调用方法

public class FileReceiveTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
ReceiveFileThread rf=new ReceiveFileThread();
rf.start();
}
}


注意一定要先启动接受方,在启动发送方
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flask是一个基于Python的轻量级Web应用框架,它提供了一种简单而灵活的方式来构建Web应用程序。断点是指在文件上或下载过程中,如果中断了连接或者出现其他异常情况,可以从中断的位置继输而不需要重新开始。 在Flask中实现断点可以通过以下步骤: 1. 在Flask应用中配置文件上的最大大小,可以使用`app.config['MAX_CONTENT_LENGTH']`来设置最大文件大小。 2. 在前端页面中使用HTML的`<input type="file">`标签来实现文件上功能。 3. 在后端的路由函数中,使用`request.files`获取上的文件对象。 4. 判断是否存在已上的部分文件,可以通过检查请求头中的`Range`字段来判断是否有断点的需求。 5. 如果有断点的需求,可以通过读取已上的部分文件,然后在继时将数据追加到已上的文件中。 6. 如果没有断点的需求,直接保存上的文件即可。 下面是一个简单的示例代码: ```python from flask import Flask, request app = Flask(__name__) @app.route('/upload', methods=['POST']) def upload(): file = request.files['file'] if 'Range' in request.headers: # 断点逻辑 range_header = request.headers['Range'] # 解析Range字段,获取已上的文件大小 # 根据已上的文件大小,将数据追加到已上的文件中 else: # 直接保存上的文件 file.save('path/to/save/file') return 'Upload success' if __name__ == '__main__': app.run() ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值