我有一个 EJB 客户端,它需要从 EJB 服务器(JBoss) 检索一个大文件。
实现这一点的明显方法是服务器提供一个 EJB 外观,其方法如下:
public byte[] getFile(String fileName);
这意味着,将整个文件加载到内存中的字节数组中,然后在线发送这个字节数组。
问题是这种方法将整个文件加载到内存中,并且由于文件很大,它会溢出。
有没有办法克服这个问题?
我有一个 EJB 客户端,它需要从 EJB 服务器(JBoss) 检索一个大文件。
实现这一点的明显方法是服务器提供一个 EJB 外观,其方法如下:
public byte[] getFile(String fileName);
这意味着,将整个文件加载到内存中的字节数组中,然后在线发送这个字节数组。
问题是这种方法将整个文件加载到内存中,并且由于文件很大,它会溢出。
有没有办法克服这个问题?
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();
}
}
RMIIO库正是为这种情况而构建的。它甚至包括 @DavidBlevins 解决方案DirectRemoteInputStream的实现。
您可以使用包装在 BytearrayOutputStream 中的 ZipOutputStream。此操作将允许您返回压缩字节数组,首先使用您的方法声明,以减少 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 调用返回文件的位置,然后在另一个过程中处理下载,在这里查看更多关于如何下载大文件的信息如何使用 Java 从 Internet 下载和保存文件?
我采用的方法(注意你只适用于s)是从 EJB@LocalBean
写入 a并返回 a以检索数据并将其从客户端删除。 也可以使用,但请注意不是.File.createTempFile
File
Path
Serializable
但是,您也可以将其写入由 HTTP 服务器托管的文件并稍后从那里检索它。然后发送 HTTPDELETE
请求以删除该文件。您的 EJB 将改为返回一个java.net.URI
.