您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(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ò)程畫成圖就是下面這樣:
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ì)有是否接收的提示框
點(diǎn)擊是后,開(kāi)始接收,點(diǎn)擊否就取消
至此就成功結(jié)束了!
看完上述內(nèi)容,你們對(duì)如何使用Java Socket實(shí)現(xiàn)文件的斷點(diǎn)續(xù)傳有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(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)容。