简体   繁体   English

从远程EJB调用返回大文件

[英]Returning huge file from a remote EJB call

I have an EJB client that needs to retrieve a large file from an EJB server (JBoss). 我有一个EJB客户端需要从EJB服务器 (JBoss)检索一个大文件

The evident way to implement this is the server to offer a EJB facade with a method like this one: 实现这一点的明显方法是使用如下方法提供EJB外观的服务器:

public byte[] getFile(String fileName);

That means, loading the whole file in memory , in a byte array, and then sending this byte array on the wire. 这意味着, 将整个文件加载到内存中 ,以字节数组形式,然后在线路上发送此字节数组。

The problem is that this approach loads the whole file in memory, and since the file is huge, it would overflow it. 问题是这种方法将整个文件加载到内存中,并且由于文件很大,它会溢出它。

Is there any option to overcome this problem? 有没有选择来克服这个问题?

HTTP would be a better choice, but that said, try this serialization trick: 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();
    }
}

The RMIIO library was built for exactly this situation. RMIIO库就是针对这种情况而构建的。 It even includes an implementation of @DavidBlevins solution, the DirectRemoteInputStream . 它甚至包括@DavidBlevins解决方案的实现,即DirectRemoteInputStream

You may use ZipOutputStream, which wrapped in BytearrayOutputStream. 您可以使用ZipOutputStream,它包含在BytearrayOutputStream中。 This action will allow you to return compressed byte array, using you method declaration in the first place, in order to decrease overhead of RMI transmition. 此操作将允许您首先使用方法声明返回压缩字节数组,以减少RMI传输的开销。

RMI protocol is a totally bad solution for sending large files. RMI协议是发送大文件的完全错误的解决方案。 A possible but quiet inefficient solution is splitting your file in small chunks, send them from EJB and reassemble file on the client-side. 一个可能但安静的低效解决方案是将文件分成小块,从EJB发送它们并在客户端重新组装文件。 Something like this: 像这样的东西:

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下载并保存文件?

The approach I took (mind you only works for @LocalBean s) is to write to a File.createTempFile from the EJB and return a File to retrieve the data and delete it from the client. 我采用的方法(介意你只适用于@LocalBean )是从EJB写入File.createTempFile并返回一个File来检索数据并从客户端删除它。 Path may be used as well, but note that it is not Serializable . Path也可以使用,但请注意它不是可Serializable

However, you can also make it write to a file hosted by an HTTP server and retrieve it from there later. 但是,您也可以将其写入由HTTP服务器托管的文件,并在以后从那里检索它。 Then send an HTTP DELETE request to delete the file afterwards. 然后发送HTTP DELETE请求以删除文件。 Your EJB would instead return a java.net.URI . 您的EJB将返回java.net.URI

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

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