5

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

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

public byte[] getFile(String fileName);

这意味着,将整个文件加载到内存中的字节数组中,然后在线发送这个字节数组。

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

有没有办法克服这个问题?

4

6 回答 6

7

HTTP would be a better choice, but that said, try this serialization trick:

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();
    }
}
于 2012-05-25T01:34:42.763 回答
5

RMIIO库正是为这种情况而构建的。它甚至包括 @DavidBlevins 解决方案DirectRemoteInputStream的实现。

于 2012-05-25T02:18:03.950 回答
2

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

于 2012-10-04T07:38:48.930 回答
1

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

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

...
public FileMetadata getFileMetadata(String fileName) {...}
public byte[] getFileChunk(String fileName, long chunkNumber) {...}
...
于 2012-05-24T19:40:31.277 回答
0

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

于 2012-10-05T21:22:46.010 回答
0

我采用的方法(注意你只适用于s)是从 EJB@LocalBean写入 a并返回 a以检索数据并将其从客户端删除。 也可以使用,但请注意不是.File.createTempFileFilePathSerializable

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

于 2015-08-20T12:27:01.797 回答