溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用Java Socket實(shí)現(xiàn)文件的斷點(diǎn)續(xù)傳

發(fā)布時(shí)間:2020-07-14 14:12:51 來(lái)源:億速云 閱讀:233 作者:Leah 欄目:編程語(yǔ)言

今天就跟大家聊聊有關(guān)如何使用Java Socket實(shí)現(xiàn)文件的斷點(diǎn)續(xù)傳,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

前段時(shí)間因?yàn)槿蝿?wù)需要本人這個(gè)java渣渣開(kāi)始研究如何用java實(shí)現(xiàn)簡(jiǎn)單的文件斷點(diǎn)續(xù)傳。所謂的文件斷點(diǎn)續(xù)傳,我的理解是文件在傳輸過(guò)程中因?yàn)槟承┰虺绦蛲V惯\(yùn)行文件終止傳輸,下一次重新傳輸文件的時(shí)候還能從上一次傳輸?shù)奈恢瞄_(kāi)始傳輸,而不需要重新從頭開(kāi)始。

文件傳輸?shù)倪^(guò)程分為發(fā)送方和接收方,最終我的思路是這樣的:

1:傳輸開(kāi)始之前發(fā)送方先向接收方發(fā)送一個(gè)確認(rèn)信息,然后再向接收方發(fā)送準(zhǔn)備發(fā)送的文件的文件名
    2:接收方收到確認(rèn)信息之后,接收從發(fā)送方發(fā)送過(guò)來(lái)的文件名,接收完之后向發(fā)送方發(fā)送一個(gè)確認(rèn)信息表示文件名接收完畢,然后接收方根據(jù)收到的文件名創(chuàng)建一個(gè)“.temp”File對(duì)象和一個(gè)“.temp”RandomAccessFile對(duì)象。獲取這個(gè)File對(duì)象所對(duì)應(yīng)文件的長(zhǎng)度(大?。ㄟ@個(gè)長(zhǎng)度就是接收方已經(jīng)接受的長(zhǎng)度,如果之前沒(méi)有接收過(guò)這個(gè)文件,長(zhǎng)度就為0),并把文件長(zhǎng)度發(fā)送給發(fā)送方。
    3:發(fā)送方收到確認(rèn)信息之后,接收接受方發(fā)送的文件長(zhǎng)度,然后向接收方發(fā)送準(zhǔn)備發(fā)送的文件的總長(zhǎng)度,并向接收方發(fā)送一個(gè)確認(rèn)信息。然后根據(jù)接收方發(fā)送的文件長(zhǎng)度,從文件對(duì)應(yīng)長(zhǎng)度的位置開(kāi)始發(fā)送。
    4:接收方收到確認(rèn)信息之后,接受發(fā)送方發(fā)送過(guò)來(lái)的數(shù)據(jù),然后從此文件的末尾寫入。接受完成之后再將“.temp”文件重命名為正常的文件名。

把過(guò)程畫成圖就是下面這樣:

如何使用Java Socket實(shí)現(xiàn)文件的斷點(diǎn)續(xù)傳

ok”表示確認(rèn)信息

能夠?qū)崿F(xiàn)斷點(diǎn)續(xù)傳的關(guān)鍵就是使用了RandomAccessFile,此類的實(shí)例支持對(duì)隨機(jī)訪問(wèn)文件的讀取和寫入。

加入一些如進(jìn)度條、文件選擇器之類的GUI,最終的主要代碼如下:

發(fā)送方代碼:

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();
//讀取文件已發(fā)送的大小
         dos.writeLong(rad.length());
          dos.writeUTF("
ok
");
         dos.flush();
          long offset=size;
//字節(jié)偏移量
          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();
//進(jìn)度條
           label=new JLabel(file.getName()+" 
發(fā)送中
");
          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
);
         
 //從文件指定位置開(kāi)始傳輸
          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()+" 
發(fā)送完成
");
           }
      dis.close();
      dos.close();
      rad.close();
    } 
catch
 (IOException e) {
        
  // TODO Auto-generated catch block
      label.setText("
 取消發(fā)送,連接關(guān)閉
");
    }
finally
 {
      frame.dispose();
    }
  }
}
class
 CancelActionListener 
implements
 ActionListener{
  
public void
 actionPerformed(ActionEvent e3){
    
try
 {
      label.setText(" 
取消發(fā)送,連接關(guān)閉
");
      JOptionPane.showMessageDialog(frame, "
取消發(fā)送給,連接關(guān)閉!
", "
提示:
", 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, "
是否接收文件","文件傳輸請(qǐng)求:
", 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);
//發(fā)送已接收的大小
      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();
//進(jìn)度條
      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+" 
結(jié)束接收
");
      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("
 已取消接收,連接關(guān)閉!
");
    }
finally
 {
      frame.dispose();
    }
  }
class
 CancelActionListener 
implements
 ActionListener{
  
public void
 actionPerformed(ActionEvent e){
    
try
 {
      dis.close();
      dos.close();
      rad.close();
      JOptionPane.showMessageDialog(frame, "
已取消接收,連接關(guān)閉!
", "
提示:
", JOptionPane.
INFORMATION_MESSAGE
);
      label.setText(" 
取消接收,連接關(guān)閉
");
    } 
catch
 (IOException e1) {
    }
   }
  }
}

接收方測(cè)試:

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

發(fā)送方測(cè)試:

public class FileSendTest{
//發(fā)送方
  
public static void
 main(String[] args) {
    
// TODO Auto-generated method stub
    SendFile sf=new SendFile();
    sf.start();
  }
}

注意 先運(yùn)行接收方代碼再運(yùn)行發(fā)送方代碼,測(cè)試的時(shí)候我們選一個(gè)大一點(diǎn)的文件,我這里選了個(gè)電影文件,運(yùn)行結(jié)果如下:

首先會(huì)有是否接收的提示框

如何使用Java Socket實(shí)現(xiàn)文件的斷點(diǎn)續(xù)傳

點(diǎn)擊是后,開(kāi)始接收,點(diǎn)擊否就取消

如何使用Java Socket實(shí)現(xiàn)文件的斷點(diǎn)續(xù)傳

至此就成功結(jié)束了!

看完上述內(nèi)容,你們對(duì)如何使用Java Socket實(shí)現(xiàn)文件的斷點(diǎn)續(xù)傳有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI