前段时间因为任务需要本人这个java渣渣开始研究如何用java实现简单的文件断点续传。所谓的文件断点续传,我的理解是文件在传输过程中因为某些原因程序停止运行文件终止传输,下一次重新传输文件的时候还能从上一次传输的位置开始传输,而不需要重新从头开始。

文件传输的过程分为发送方和接收方,最终我的思路是这样的:

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

把过程画成图就是下面这样:

ok”表示确认信息
能够实现断点续传的关键就是使用了RandomAccessFile,此类的实例支持对随机访问文件的读取和写入。
加入一些如进度条、文件选择器之类的GUI,最终的主要代码如下:
发送方代码:

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 SendFile 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 SendFile(){
    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);

          //传输界面
         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) {

   }
   }
 }

}

接收方代码:

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 ReceiveFile 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 ReceiveFile(){
     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("FileReceive 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 
    ReceiveFile rf=new ReceiveFile();
    rf.start();
  }

}

发送方测试:

public class FileSendTest{//发送方

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

}

注意 先运行接收方代码再运行发送方代码,测试的时候我们选一个大一点的文件,我这里选了个电影文件,运行结果如下:
首先会有是否接收的提示框

点击是后,开始接收,点击否就取消

至此就成功结束了!

转载于:https://www.cnblogs.com/zhaosq/p/10471882.html

Java-Socket实现文件的断点续传相关推荐

  1. Java Socket实现文件传输

    阿里云双11服务器优惠(年度最佳优惠): A:1核2GB 1M 服务器年69元 B:1核2GB 1M 服务器三年180元 C:2核4GB 1~10M 服务器三年567元(强烈推荐) D:4核8GB 1 ...

  2. java socket安全策略文件

    获取策略文件的Java服务器端代码import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOExce ...

  3. 基于Java Socket的文件UpLoad代码(完美版)-用递归解决java的目录树遍历

    http://blog.csdn.net/dongfengsun/archive/2007/12/12/1930577.aspx 上次用J2SE写了一个文件夹传递工具,把所有文件都以字节流的形式写入到 ...

  4. Java Socket编程 文件传输(客户端从服务器下载一个文件)

    服务器(Server) [java] view plaincopy  package com.socket.sample;      import java.io.BufferedInputStrea ...

  5. java socket 读取文件_Java中Socket下载一个文本文件

    package com.lanqiao.demo2; import java.io.BufferedInputStream; import java.io.FileInputStream; impor ...

  6. java socket 读取文件_java中ServerSocket读取文件流不是分行读取

    在学习socket的TCP通讯 在使用 TCP传一个文件时 遇到这样两个问题 1. 服务端流读取时一次性读了所有内容 而不是分行读取 2. 自动刷新不生效 代码如下 package com.fuge. ...

  7. dout java,java socket 发送文件

    客户端 public class ClientTcpSend { public static void main(String[] args) { int length = 0; byte[] sen ...

  8. 文件绑定java socket多线程网络传输多个文件Strut2教程-java教程

    题记:写这篇博客要主是加深自己对文件绑定的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢. 由于要需究研了下用java socket传输文件,由于要需传输多个文件,因此,采用了多线程 ...

  9. Android之在Java socket作为服务器里面返回数据头部怎么写入浏览器需要下载文件的文件名

    1 问题 Android app里面写了一个Java socket的简单服务器,在浏览器里面输入相应的IP和端口访问服务器下载文件,Java socket怎么写返回数据的头部信息,浏览器才知道需要下载 ...

  10. java socket 传输压缩文件_java基于socket传输zip文件功能示例

    本文实例讲述了java基于socket传输zip文件的方法.分享给大家供大家参考,具体如下: 服务器端程序: import java.io.*; import java.net.*; import j ...

最新文章

  1. java中抽象接口_一篇文章让你彻底理解java中抽象类和接口
  2. r语言删除csv中na行_r语言,csv数据,提取特定行
  3. 网络编程学习笔记(获取所有网络接口)
  4. iOS 使用UI控件的外观协议UIAppearance进行设置默认UI控件样式
  5. winform模拟登陆网页_winform跳转到制定的网页并自动实现登陆功能
  6. 策略模式(Strategy)简介
  7. mysql自增id用完了_MySQL表自增id用完了该怎么办?
  8. spring boot 配置网关时404错误_网关Spring Cloud Gateway科普
  9. win8卸载mysql数据库,彻底卸载win8自带的metro应用的方法
  10. 细聊分布式ID生成方法-2
  11. Linux系统各个目录的作用(中英文对照)
  12. 查看anaconda环境下各个包的版本
  13. cropbox php,jQuery用户头像裁剪插件cropbox.js使用详解
  14. 硅谷系创业公司,这家深耕物联网22年的Fabless终于走到上市关口
  15. MySQL中的保留字
  16. 计算机图形学学习笔记(4.1)画线算法
  17. 肖申克的救赎-救赎自己的心灵
  18. shell 获取当前目录的路径
  19. 8.微信小程序-Mobx数据共享(类似vuex)
  20. java编程技术交流

热门文章

  1. SpringMVC启动过程详解(li)
  2. (转)基于libRTMP的流媒体直播之 AAC、H264 推送
  3. DbContext 和ObjectContext两者的区别
  4. 通知:即日起本博客暂停更新,请移步至yanxin8.com获取最新文章
  5. 表示探索、探究的几个词
  6. 微软的Surface平板电脑RT版,RT是什么缩写?|转|
  7. import python settings from_Python的Django框架中settings文件的部署建议
  8. c语言 %-20s,一次 Rust 和C语言的混搭
  9. 计算机网络日志查询,系统资源管理_百络网警内网管理软件_电脑配置统计,系统日志,日志查询...
  10. 制作简单的java应用程序_使用exe4j工具制作简单的java应用程序