我有一个EJB客户端,需要从EJB服务器(JBoss)检索大文件。
实现这一点的明显方法是使用类似这样的方法提供EJB外观的服务器:
public byte[] getFile(String fileName);
这意味着,在内存中加载整个文件,在一个字节数组中,然后在线上发送这个字节数组。
问题是这种方法将整个文件加载到内存中,并且由于文件很大,它会溢出它。
有没有办法解决这个问题?
答案 0 :(得分:6)
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();
}
}
答案 1 :(得分:5)
RMIIO库是针对这种情况而构建的。它甚至包括@DavidBlevins解决方案的实现,DirectRemoteInputStream。
答案 2 :(得分:2)
您可以使用ZipOutputStream,它包含在BytearrayOutputStream中。此操作将允许您首先使用方法声明返回压缩字节数组,以减少RMI传输的开销。
答案 3 :(得分:1)
RMI协议是发送大文件的完全错误的解决方案。一个可能但安静的低效解决方案是将文件分成小块,从EJB发送它们并在客户端重新组装文件。像这样:
public class FileMetadata {
....
private long chunkCount;
private long chunkSize;
....
}
...
public FileMetadata getFileMetadata(String fileName) {...}
public byte[] getFileChunk(String fileName, long chunkNumber) {...}
...
答案 4 :(得分:0)
我会重新考虑你的架构,恕我直言你应该快速保持你的ejb调用,如何从ejb调用返回文件的位置,然后在另一个程序中处理downlod,看看这里有关如何下载的更多信息大文件How to download and save a file from Internet using Java?
答案 5 :(得分:0)
我采用的方法(介意你只适用于@LocalBean
)是从EJB写入File.createTempFile
并返回File
来检索数据并从中删除它客户。也可以使用Path
,但请注意,它不是Serializable
。
但是,您也可以将其写入由HTTP服务器托管的文件,并在以后从那里检索它。然后发送HTTP DELETE
请求以删除该文件。您的EJB将返回java.net.URI
。