繁体   English   中英

从远程EJB调用返回大文件

[英]Returning huge file from a remote EJB call

我有一个EJB客户端需要从EJB服务器 (JBoss)检索一个大文件

实现这一点的明显方法是使用如下方法提供EJB外观的服务器:

public byte[] getFile(String fileName);

这意味着, 将整个文件加载到内存中 ,以字节数组形式,然后在线路上发送此字节数组。

问题是这种方法将整个文件加载到内存中,并且由于文件很大,它会溢出它。

有没有选择来克服这个问题?

HTTP将是一个更好的选择,但是,说,尝试这个序列化技巧:

import java.io.*;

public class FileContent implements Serializable {

    private transient File file;

    public FileContent() {
    }

    public FileContent(File file) {
        this.file = file;
    }

    private void writeObject(ObjectOutputStream out) throws IOException {
        // 1. write the file name
        out.writeUTF(file.getAbsolutePath());

        // 2. write the length
        out.writeLong(file.length());

        // 3. write the content
        final InputStream in = new BufferedInputStream(new FileInputStream(file));
        final byte[] buffer = new byte[1024];

        int length;
        while ((length = in.read(buffer)) != -1) {
            out.write(buffer, 0, length);
        }
        out.flush();
        in.close();
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        // 1. read the file name
        final String path = in.readUTF();

        // 2. read the length
        long remaining = in.readLong();

        // 3. read the content
        file = new File(path);
        final OutputStream out = new BufferedOutputStream(new FileOutputStream(file));

        final byte[] buffer = new byte[1024];

        while (true) {
            int length = in.read(buffer, 0, (int) Math.min(remaining, buffer.length));
            if (length == -1) break;

            out.write(buffer, 0, length);

            remaining -= length;
            if (remaining <= 0) break;
        }
        out.flush();
        out.close();
    }
}

RMIIO库就是针对这种情况而构建的。 它甚至包括@DavidBlevins解决方案的实现,即DirectRemoteInputStream

您可以使用ZipOutputStream,它包含在BytearrayOutputStream中。 此操作将允许您首先使用方法声明返回压缩字节数组,以减少RMI传输的开销。

RMI协议是发送大文件的完全错误的解决方案。 一个可能但安静的低效解决方案是将文件分成小块,从EJB发送它们并在客户端重新组装文件。 像这样的东西:

public class FileMetadata {
    ....
    private long chunkCount;
    private long chunkSize;
    ....
}

...
public FileMetadata getFileMetadata(String fileName) {...}
public byte[] getFileChunk(String fileName, long chunkNumber) {...}
...

我会重新考虑你的架构,恕我直言你应该快速保持你的ejb调用,如何从ejb调用返回文件的位置然后在另一个程序中处理downlod,看看这里有关如何下载大文件的更多信息使用Java从Internet下载并保存文件?

我采用的方法(介意你只适用于@LocalBean )是从EJB写入File.createTempFile并返回一个File来检索数据并从客户端删除它。 Path也可以使用,但请注意它不是可Serializable

但是,您也可以将其写入由HTTP服务器托管的文件,并在以后从那里检索它。 然后发送HTTP DELETE请求以删除文件。 您的EJB将返回java.net.URI

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM