阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

基于RMI服务传输大文件的完整解决方案

384次阅读
没有评论

共计 16318 个字符,预计需要花费 41 分钟才能阅读完成。

基于 RMI 服务传输大文件,分为上传和下载两种操作,需要注意的技术点主要有三方面,第一,RMI 服务中传输的数据必须是可序列化的。第二,在传输大文件的过程中应该有进度提醒机制,对于大文件传输来说,这点很重要,因为大文件的传输时间周期往往比较长,必须实时告知用户大文件的传输进度。第三,针对大文件的读取方式,如果采用一次性将大文件读取到 byte[]中是不现实的,因为这将受制于 JVM 的可用内存,会导致内存溢出的问题。

笔者实验的基于 RMI 服务传输大文件的解决方案,主要就是围绕以上三方面进行逐步解决的。下面将分别就上传大文件和下载大文件进行阐述。

1. 基于 RMI 服务上传大文件

1.1. 设计思路

上传大文件分为两个阶段,分别为“CS 握手阶段”和“文件内容上传更新阶段”。

CS 握手阶段,又可称之为客户端与服务端之间的基本信息交换阶段。客户端要确定待上传的本地文件和要上传到服务端的目标路径。读取本地文件,获取文件长度,将本地文件长度、本地文件路径和服务端目标路径等信息通过接口方法传递到服务端,然后由服务端生成具有唯一性的 FileKey 信息,并返回到客户端,此 FileKey 作为客户端与服务端之间数据传输通道的唯一标示。这些信息数据类型均为 Java 基本数据类型,因此都是可序列化的。此接口方法就称之为“握手接口”,通过 CS 握手,服务端能确定三件事:哪个文件要传输过来、这个文件的尺寸、这个文件将存放在哪里,而这三件刚好是完成文件上传的基础。

然后就是“文件内容上传更新阶段”。客户端打开文件后,每次读取一定量的文件内容,譬如每次读取(1024 * 1024 * 2)byte 的数据,并将此批数据通过“上传更新”接口方法传输到服务端,由服务端写入输出流中,同时检查文件内容是否已经传输完毕,如果已经传输完毕,则执行持久化 flush 操作在服务端生成文件;客户端每次传输一批数据后,就更新“已传输数据总量”标示值,并与文件总长度进行比对计算,从而得到文件上传进度,实时告知用户。综上所述,客户端循环读取本地文件内容并传输到服务端,直到文件内容读取上传完毕为止。

1.2. 功能设计

1.2.1 文件上传相关状态信息的管理

大文件上传的过程中,在服务端,最重要的是文件上传过程相关状态信息的精确管理,譬如,文件总长度、已上传字节总数、文件存储路径等等。而且要保证在整个上传过程中数据的实时更新和绝对不能丢失,并且在文件上传完毕后及时清除这些信息,以避免服务端累计过多失效的状态数据。

鉴于此,我们设计了一个类 RFileUploadTransfer 来实现上述功能。代码如下:

/**
 * Description: 文件上传过程相关状态信息封装类。<br>
 * Copyright: Copyright (c) 2016<br>
 * Company: 河南电力科学研究院智能电网所 <br>
 * @author shangbingbing 2016-01-01 编写
 * @version 1.0
 */
public class RFileUploadTransfer implements Serializable {
    private static final long serialVersionUID = 1L;
    private String fileKey;
    // 客户端文件路径
    private String srcFilePath;
    // 服务端上传目标文件路径
    private String destFilePath;
    // 文件尺寸
    private int fileLength = 0;
    // 已传输字节总数
    private int transferByteCount = 0;
    // 文件是否已经完整写入服务端磁盘中
    private boolean isSaveFile = false;
    private OutputStream out = null;
   
    public RFileUploadTransfer(String srcFilePath, int srcFileLength, String destFilePath) {
        this.fileKey = UUID.randomUUID().toString();
        this.srcFilePath = srcFilePath;
        this.fileLength = srcFileLength;
        this.destFilePath = destFilePath;
       
        File localFile = new File(this.destFilePath);
        if(localFile.getParentFile().exists() == false) {
            localFile.getParentFile().mkdirs();
        }
        try {
            this.out = new FileOutputStream(localFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
   
    public String getFileKey() {
        return fileKey;
    }
    public String getSrcFilePath() {
        return srcFilePath;
    }
    public String getDestFilePath() {
        return destFilePath;
    }
    public boolean isSaveFile() {
        return isSaveFile;
    }
   
    public void addContentBytes(byte[] bytes) {
        try {
            if(bytes == null || bytes.length == 0) {
                return;
            }
            if(this.transferByteCount + bytes.length > this.fileLength) {
                // 如果之前已经传输的数据长度 + 本批数据长度 > 文件长度的话,说明这批数据是最后一批数据了;
                // 由于本批数据中可能会存在有空字节,所以需要筛选出来。
                byte[] contents = new byte[this.fileLength – this.transferByteCount];
                for(int i=0;i<contents.length;i++) {
                    contents[i] = bytes[i];
                }
                this.transferByteCount = this.fileLength;
                this.out.write(contents);
            } else {
                // 说明本批数据并非最后一批数据,文件还没有传输完。
                this.transferByteCount += bytes.length;
                this.out.write(bytes);
            }
            if(this.transferByteCount >= this.fileLength) {
                this.out.flush();
                this.isSaveFile = true;
                if(this.out != null) {
                    try {
                        this.out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

然后,在 RMI 服务接口方法实现类中构建一个线程安全的集合,用来存储管理各个大文件的传输过程,代码如下:

/**
* 上传文件状态监视器
*/
private Hashtable<String,RFileUploadTransfer> uploadFileStatusMonitor = new Hashtable<String,RFileUploadTransfer>();

1.2.2 CS 握手接口设计

CS 握手接口名称为 startUploadFile,主要功能就是传输交换文件基本信息,构建文件上传过程状态控制对象。其在接口实现类中的代码如下所示:

@Override
public String startUploadFile(String localFilePath, int localFileLength, String remoteFilePath) throws RemoteException {
    RFileUploadTransfer fileTransfer = new RFileUploadTransfer(localFilePath,localFileLength,remoteFilePath);
    if(this.uploadFileStatusMonitor.containsKey(fileTransfer.getFileKey())) {
        this.uploadFileStatusMonitor.remove(fileTransfer.getFileKey());
    }
    this.uploadFileStatusMonitor.put(fileTransfer.getFileKey(), fileTransfer);
    return fileTransfer.getFileKey();
}

1.2.3 文件内容上传更新接口设计
文件内容上传更新接口名称为 updateUploadProgress,主要功能是接收客户端传输过来的文件内容 byte[]信息。其在接口实现类中的代码如下所示:

@Override
public boolean updateUploadProgress(String fileKey, byte[] contents) throws RemoteException {
    if(this.uploadFileStatusMonitor.containsKey(fileKey)) {
        RFileUploadTransfer fileTransfer = this.uploadFileStatusMonitor.get(fileKey);
        fileTransfer.addContentBytes(contents);
        if(fileTransfer.isSaveFile()) {
            this.uploadFileStatusMonitor.remove(fileKey);
        }
    }
    return true;
}

1.2.4 客户端设计

客户端的主要功能是打开本地文件,按批读取文件内容 byte[]信息,调用 RMI 接口方法进行传输,同时进行传输进度的提醒。下面是笔者本人采用 swing 开发的测试代码,采用 JProgressBar 进行进度的实时提醒。

progressBar.setMinimum(0);
progressBar.setMaximum(100);
InputStream is = null;
try {
    File srcFile = new File(localFilePath);
    int fileSize = (int)srcFile.length();
    String fileKey = getFileManageService().startUploadFile(localFilePath, fileSize, remoteFilePath);
                           
    byte[] buffer = new byte[1024 * 1024 * 2];
    int offset = 0;
    int numRead = 0;
    is = new FileInputStream(srcFile);
    while(-1 != (numRead=is.read(buffer))) {
        offset += numRead;
        getFileManageService().updateUploadProgress(fileKey, buffer);
        double finishPercent = (offset * 1.0 / fileSize) * 100;
        progressBar.setValue((int)finishPercent);
    }
    if(offset != fileSize) {
        throw new IOException(“ 不能完整地读取文件 ” + localFilePath);
    } else {
        progressBar.setValue(100);
    }
} catch (Exception ex) {
    ex.printStackTrace();
} finally {
    try {
        if(is != null) {
            is.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

实例界面截图如下所示:

基于 RMI 服务传输大文件的完整解决方案

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-02/128710p2.htm

2. 基于 RMI 服务下载大文件

2.1. 设计思路

下载大文件分为两个阶段,分别为“CS 握手阶段”和“文件内容下载更新阶段”。

CS 握手阶段,又可称之为客户端与服务端之间的基本信息交换阶段。服务端读取待下载的文件,获取文件长度,生成具有唯一性的 FileKey 信息,并将文件长度、FileKey 信息传输到客户端,此 FileKey 作为客户端与服务端之间数据传输通道的唯一标示。这些信息数据类型均为 Java 基本数据类型,因此都是可序列化的。此接口方法就称之为“握手接口”,通过 CS 握手,客户端能确定两件事:哪个文件要下载、这个文件的尺寸,而这两件刚好是完成文件下载的基础。

然后就是“文件内容下载更新阶段”。服务端打开文件后,每次读取一定量的文件内容,譬如每次读取(1024 * 1024 * 2)byte 的数据,并将此批数据通过“下载更新”接口方法传输到客户端,由客户端写入输出流中,同时检查文件内容是否已经传输完毕,如果已经传输完毕,则执行持久化 flush 操作在客户端生成文件;客户端每接收一批数据后,就更新“已下载数据总量”标示值,并与文件总长度进行比对计算,从而得到文件下载进度,实时告知用户。综上所述,客户端循环获取服务端传输过来的文件内容,直到服务端文件内容读取传输完毕为止。

2.2. 功能设计

2.2.1 文件下载相关状态信息的管理

大文件下载的过程中,在服务端,最重要的是文件下载过程相关状态信息的精确管理,譬如,文件总长度、已下载字节总数等等。而且要保证在整个下载过程中数据的实时更新和绝对不能丢失,并且在文件下载完毕后及时清除这些信息,以避免服务端累计过多失效的状态数据。

鉴于此,我们设计了一个类 RFileDownloadTransfer 来实现上述功能。代码如下:

/**
 * Description: 文件下载过程相关状态信息封装类。<br>
 * Copyright: Copyright (c) 2016<br>
 * Company: 河南电力科学研究院智能电网所 <br>
 * @author shangbingbing 2016-01-01 编写
 * @version 1.0
 */
public class RFileDownloadTransfer implements Serializable {
    private static final long serialVersionUID = 1L;
    private String fileKey;
    // 服务端待下载文件路径
    private String srcFilePath;
    // 待下载文件尺寸
    private int fileLength = 0;
    private InputStream inputStream = null;
    // 已经传输文件内容字节总数
    private int transferByteCount = 0;
    // 服务端待下载文件是否已经读取完毕
    private boolean isReadFinish = false;
   
    public RFileDownloadTransfer(String srcFilePath) {
        this.fileKey = UUID.randomUUID().toString();
        this.srcFilePath = srcFilePath;
        File srcFile = new File(srcFilePath);
        this.fileLength = (int)srcFile.length();
        try {
            this.inputStream = new FileInputStream(srcFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    public String getFileKey() {
        return fileKey;
    }
    public String getSrcFilePath() {
        return srcFilePath;
    }
    public int getFileLength() {
        return fileLength;
    }
    public boolean isReadFinish() {
        return isReadFinish;
    }
    public byte[] readBytes() {
        try {
            if(this.inputStream == null) {
                return null;
            }
            byte[] buffer = new byte[1024 * 1024 * 5];
            this.inputStream.read(buffer);
            this.transferByteCount += buffer.length;
            if(this.transferByteCount >= this.fileLength) {
                this.isReadFinish = true;
                this.transferByteCount = this.fileLength;
            }
            return buffer;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
   
    public void closeInputStream() {
        if(this.inputStream != null) {
            try {
                this.inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

然后,在 RMI 服务接口方法实现类中构建一个线程安全的集合,用来存储管理各个大文件的传输过程,代码如下:

/**
* 下载文件状态监视器
*/
private Hashtable<String,RFileDownloadTransfer> downloadFileStatusMonitor = new Hashtable<String,RFileDownloadTransfer>();

2.2.2 CS 握接口设计

CS 握手接口名称为 startDownloadFile,主要功能就是传输交换文件基本信息,构建文件下载过程状态控制对象。其在接口实现类中的代码如下所示:

@Override
public Map<String, String> startDownloadFile(String srcFilePath) throws RemoteException {
    RFileDownloadTransfer fileTransfer = new RFileDownloadTransfer(srcFilePath);
    if(this.downloadFileStatusMonitor.containsKey(fileTransfer.getFileKey())) {
        this.downloadFileStatusMonitor.remove(fileTransfer.getFileKey());
    }
    this.downloadFileStatusMonitor.put(fileTransfer.getFileKey(), fileTransfer);
    Map<String,String> fileInfoList = new HashMap<String,String>();
    fileInfoList.put(“fileLength”, String.valueOf(fileTransfer.getFileLength()));
    fileInfoList.put(“fileKey”, fileTransfer.getFileKey());
    return fileInfoList;
}

2.2.3 文件内容下载更新接口设计

文件内容下载更新接口名称为 updateDownloadProgress,主要功能是接收客户端传输过来的文件内容 byte[]信息。其在接口实现类中的代码如下所示:

@Override
public byte[] updateDownloadProgress(String fileKey) throws RemoteException {
    if(this.downloadFileStatusMonitor.containsKey(fileKey)) {
        RFileDownloadTransfer fileTransfer = this.downloadFileStatusMonitor.get(fileKey);
        byte[] bytes = fileTransfer.readBytes();
        if(fileTransfer.isReadFinish()) {
            fileTransfer.closeInputStream();
            this.downloadFileStatusMonitor.remove(fileKey);
        }
        return bytes;
    }
    return null;
}

2.2.4 客户端设计

客户端的主要功能是创建磁盘文件,逐批次获取文件内容 byte[]信息,并将其写入输出流中,同时进行传输进度的提醒,并最终生成完整的文件。下面是笔者本人采用 swing 开发的测试代码,采用 JProgressBar 进行进度的实时提醒。

Map<String,String> fileInfoList = getFileManageService().startDownloadFile(remoteFilePath);
int fileLength = Integer.valueOf(fileInfoList.get(“fileLength”));
String fileKey = fileInfoList.get(“fileKey”);
int transferByteCount = 0;
                   
progressBar.setMinimum(0);
progressBar.setMaximum(100);
                   
OutputStream out = new FileOutputStream(localFilePath);
while(true) {
    if(transferByteCount >= fileLength) {
        break;
    }
                       
    byte[] bytes = getFileManageService().updateDownloadProgress(fileKey);
    if(bytes == null) {
        break;
    }
                       
    if(transferByteCount + bytes.length > fileLength) {
        // 如果之前已经传输的数据长度 + 本批数据长度 > 文件长度的话,说明这批数据是最后一批数据了;
        // 那么本批数据中将会有空字节,需要筛选出来。
        byte[] contents = new byte[fileLength – transferByteCount];
        for(int i=0;i<contents.length;i++) {
            contents[i] = bytes[i];
        }
        transferByteCount = fileLength;
        out.write(contents);
    } else {
        // 说明本批数据并非最后一批数据,文件还没有传输完。
        transferByteCount += bytes.length;
        out.write(bytes);
    }
                       
    double dblFinishPercent = (transferByteCount * 1.0 / fileLength) * 100;
    int finishPercent = (int)dblFinishPercent;
    if(finishPercent > 100) {
        finishPercent = 100;
    }
    progressBar.setValue(finishPercent);
}
                   
if(transferByteCount != fileLength) {
    LogInfoUtil.printLog(“ 不能完整地读取文件 ” + remoteFilePath);
} else {
    progressBar.setValue(100);
    out.flush();
    if(out != null) {
        try {
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

实例界面截图如下所示:

基于 RMI 服务传输大文件的完整解决方案

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-02/128710.htm

基于 RMI 服务传输大文件,分为上传和下载两种操作,需要注意的技术点主要有三方面,第一,RMI 服务中传输的数据必须是可序列化的。第二,在传输大文件的过程中应该有进度提醒机制,对于大文件传输来说,这点很重要,因为大文件的传输时间周期往往比较长,必须实时告知用户大文件的传输进度。第三,针对大文件的读取方式,如果采用一次性将大文件读取到 byte[]中是不现实的,因为这将受制于 JVM 的可用内存,会导致内存溢出的问题。

笔者实验的基于 RMI 服务传输大文件的解决方案,主要就是围绕以上三方面进行逐步解决的。下面将分别就上传大文件和下载大文件进行阐述。

1. 基于 RMI 服务上传大文件

1.1. 设计思路

上传大文件分为两个阶段,分别为“CS 握手阶段”和“文件内容上传更新阶段”。

CS 握手阶段,又可称之为客户端与服务端之间的基本信息交换阶段。客户端要确定待上传的本地文件和要上传到服务端的目标路径。读取本地文件,获取文件长度,将本地文件长度、本地文件路径和服务端目标路径等信息通过接口方法传递到服务端,然后由服务端生成具有唯一性的 FileKey 信息,并返回到客户端,此 FileKey 作为客户端与服务端之间数据传输通道的唯一标示。这些信息数据类型均为 Java 基本数据类型,因此都是可序列化的。此接口方法就称之为“握手接口”,通过 CS 握手,服务端能确定三件事:哪个文件要传输过来、这个文件的尺寸、这个文件将存放在哪里,而这三件刚好是完成文件上传的基础。

然后就是“文件内容上传更新阶段”。客户端打开文件后,每次读取一定量的文件内容,譬如每次读取(1024 * 1024 * 2)byte 的数据,并将此批数据通过“上传更新”接口方法传输到服务端,由服务端写入输出流中,同时检查文件内容是否已经传输完毕,如果已经传输完毕,则执行持久化 flush 操作在服务端生成文件;客户端每次传输一批数据后,就更新“已传输数据总量”标示值,并与文件总长度进行比对计算,从而得到文件上传进度,实时告知用户。综上所述,客户端循环读取本地文件内容并传输到服务端,直到文件内容读取上传完毕为止。

1.2. 功能设计

1.2.1 文件上传相关状态信息的管理

大文件上传的过程中,在服务端,最重要的是文件上传过程相关状态信息的精确管理,譬如,文件总长度、已上传字节总数、文件存储路径等等。而且要保证在整个上传过程中数据的实时更新和绝对不能丢失,并且在文件上传完毕后及时清除这些信息,以避免服务端累计过多失效的状态数据。

鉴于此,我们设计了一个类 RFileUploadTransfer 来实现上述功能。代码如下:

/**
 * Description: 文件上传过程相关状态信息封装类。<br>
 * Copyright: Copyright (c) 2016<br>
 * Company: 河南电力科学研究院智能电网所 <br>
 * @author shangbingbing 2016-01-01 编写
 * @version 1.0
 */
public class RFileUploadTransfer implements Serializable {
    private static final long serialVersionUID = 1L;
    private String fileKey;
    // 客户端文件路径
    private String srcFilePath;
    // 服务端上传目标文件路径
    private String destFilePath;
    // 文件尺寸
    private int fileLength = 0;
    // 已传输字节总数
    private int transferByteCount = 0;
    // 文件是否已经完整写入服务端磁盘中
    private boolean isSaveFile = false;
    private OutputStream out = null;
   
    public RFileUploadTransfer(String srcFilePath, int srcFileLength, String destFilePath) {
        this.fileKey = UUID.randomUUID().toString();
        this.srcFilePath = srcFilePath;
        this.fileLength = srcFileLength;
        this.destFilePath = destFilePath;
       
        File localFile = new File(this.destFilePath);
        if(localFile.getParentFile().exists() == false) {
            localFile.getParentFile().mkdirs();
        }
        try {
            this.out = new FileOutputStream(localFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
   
    public String getFileKey() {
        return fileKey;
    }
    public String getSrcFilePath() {
        return srcFilePath;
    }
    public String getDestFilePath() {
        return destFilePath;
    }
    public boolean isSaveFile() {
        return isSaveFile;
    }
   
    public void addContentBytes(byte[] bytes) {
        try {
            if(bytes == null || bytes.length == 0) {
                return;
            }
            if(this.transferByteCount + bytes.length > this.fileLength) {
                // 如果之前已经传输的数据长度 + 本批数据长度 > 文件长度的话,说明这批数据是最后一批数据了;
                // 由于本批数据中可能会存在有空字节,所以需要筛选出来。
                byte[] contents = new byte[this.fileLength – this.transferByteCount];
                for(int i=0;i<contents.length;i++) {
                    contents[i] = bytes[i];
                }
                this.transferByteCount = this.fileLength;
                this.out.write(contents);
            } else {
                // 说明本批数据并非最后一批数据,文件还没有传输完。
                this.transferByteCount += bytes.length;
                this.out.write(bytes);
            }
            if(this.transferByteCount >= this.fileLength) {
                this.out.flush();
                this.isSaveFile = true;
                if(this.out != null) {
                    try {
                        this.out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

然后,在 RMI 服务接口方法实现类中构建一个线程安全的集合,用来存储管理各个大文件的传输过程,代码如下:

/**
* 上传文件状态监视器
*/
private Hashtable<String,RFileUploadTransfer> uploadFileStatusMonitor = new Hashtable<String,RFileUploadTransfer>();

1.2.2 CS 握手接口设计

CS 握手接口名称为 startUploadFile,主要功能就是传输交换文件基本信息,构建文件上传过程状态控制对象。其在接口实现类中的代码如下所示:

@Override
public String startUploadFile(String localFilePath, int localFileLength, String remoteFilePath) throws RemoteException {
    RFileUploadTransfer fileTransfer = new RFileUploadTransfer(localFilePath,localFileLength,remoteFilePath);
    if(this.uploadFileStatusMonitor.containsKey(fileTransfer.getFileKey())) {
        this.uploadFileStatusMonitor.remove(fileTransfer.getFileKey());
    }
    this.uploadFileStatusMonitor.put(fileTransfer.getFileKey(), fileTransfer);
    return fileTransfer.getFileKey();
}

1.2.3 文件内容上传更新接口设计
文件内容上传更新接口名称为 updateUploadProgress,主要功能是接收客户端传输过来的文件内容 byte[]信息。其在接口实现类中的代码如下所示:

@Override
public boolean updateUploadProgress(String fileKey, byte[] contents) throws RemoteException {
    if(this.uploadFileStatusMonitor.containsKey(fileKey)) {
        RFileUploadTransfer fileTransfer = this.uploadFileStatusMonitor.get(fileKey);
        fileTransfer.addContentBytes(contents);
        if(fileTransfer.isSaveFile()) {
            this.uploadFileStatusMonitor.remove(fileKey);
        }
    }
    return true;
}

1.2.4 客户端设计

客户端的主要功能是打开本地文件,按批读取文件内容 byte[]信息,调用 RMI 接口方法进行传输,同时进行传输进度的提醒。下面是笔者本人采用 swing 开发的测试代码,采用 JProgressBar 进行进度的实时提醒。

progressBar.setMinimum(0);
progressBar.setMaximum(100);
InputStream is = null;
try {
    File srcFile = new File(localFilePath);
    int fileSize = (int)srcFile.length();
    String fileKey = getFileManageService().startUploadFile(localFilePath, fileSize, remoteFilePath);
                           
    byte[] buffer = new byte[1024 * 1024 * 2];
    int offset = 0;
    int numRead = 0;
    is = new FileInputStream(srcFile);
    while(-1 != (numRead=is.read(buffer))) {
        offset += numRead;
        getFileManageService().updateUploadProgress(fileKey, buffer);
        double finishPercent = (offset * 1.0 / fileSize) * 100;
        progressBar.setValue((int)finishPercent);
    }
    if(offset != fileSize) {
        throw new IOException(“ 不能完整地读取文件 ” + localFilePath);
    } else {
        progressBar.setValue(100);
    }
} catch (Exception ex) {
    ex.printStackTrace();
} finally {
    try {
        if(is != null) {
            is.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

实例界面截图如下所示:

基于 RMI 服务传输大文件的完整解决方案

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-02/128710p2.htm

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-21发表,共计16318字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19351
评论数
4
阅读量
7979957
文章搜索
热门文章
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛NAS中安装Navidrome音乐文件中文标签乱码问题解决、安装FntermX终端

飞牛 NAS 中安装 Navidrome 音乐文件中文标签乱码问题解决、安装 FntermX 终端 问题背景 ...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
终于收到了以女儿为原型打印的3D玩偶了

终于收到了以女儿为原型打印的3D玩偶了

终于收到了以女儿为原型打印的 3D 玩偶了 前些日子参加某网站活动,获得一次实物 3D 打印的机会,于是从众多...
再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见zabbix!轻量级自建服务器监控神器在Linux 的完整部署指南

再见 zabbix!轻量级自建服务器监控神器在 Linux 的完整部署指南 在日常运维中,服务器监控是绕不开的...
免费领取huggingface的2核16G云服务器,超简单教程

免费领取huggingface的2核16G云服务器,超简单教程

免费领取 huggingface 的 2 核 16G 云服务器,超简单教程 前言 HuggingFace.co...
多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞...
星哥带你玩飞牛NAS硬件03:五盘位+N5105+双网口的成品NAS值得入手吗

星哥带你玩飞牛NAS硬件03:五盘位+N5105+双网口的成品NAS值得入手吗

星哥带你玩飞牛 NAS 硬件 03:五盘位 +N5105+ 双网口的成品 NAS 值得入手吗 前言 大家好,我...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
星哥带你玩飞牛NAS-12:开源笔记的进化之路,效率玩家的新选择

星哥带你玩飞牛NAS-12:开源笔记的进化之路,效率玩家的新选择

星哥带你玩飞牛 NAS-12:开源笔记的进化之路,效率玩家的新选择 前言 如何高效管理知识与笔记,已经成为技术...
4盘位、4K输出、J3455、遥控,NAS硬件入门性价比之王

4盘位、4K输出、J3455、遥控,NAS硬件入门性价比之王

  4 盘位、4K 输出、J3455、遥控,NAS 硬件入门性价比之王 开篇 在 NAS 市场中,威...
多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞定

多服务器管理神器 Nexterm 横空出世!NAS/Win/Linux 通吃,SSH/VNC/RDP 一站式搞...
星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

星哥带你玩飞牛NAS-16:不再错过公众号更新,飞牛NAS搭建RSS

  星哥带你玩飞牛 NAS-16:不再错过公众号更新,飞牛 NAS 搭建 RSS 对于经常关注多个微...
300元就能买到的”小钢炮”?惠普7L四盘位小主机解析

300元就能买到的”小钢炮”?惠普7L四盘位小主机解析

  300 元就能买到的 ” 小钢炮 ”?惠普 7L 四盘位小主机解析 最近...