Java-Socket实现文件的断点续传
? ? ? ? 前段時間因為任務需要本人這個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实现文件的断点续传的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: input禁止鼠标滚轮改变数值
- 下一篇: Java成神之路[转]