我得到了服务器和客户端应用程序,它们在发送小文件的同时工作得很好,但是当我尝试发送例如700mb的电影文件时它给了我
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
我搜索了互联网并发现了一些关于发送大文件的教程,但是对它们不太了解,但我认为我的问题是写文件。
这是服务器用来编写我的文件的代码:
output = new FileOutputStream(directory + "/" + fileName);
long size = clientData.readLong();
byte[] buffer = new byte[1024];
while (size > 0 && (bytesRead = clientData.read(buffer, 0, (int) Math.min(buffer.length, size))) != -1) {
output.write(buffer, 0, bytesRead);
size -= bytesRead;
}
output.close();
以下是我的客户端用来发送文件的代码:
byte[] fileLength = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
dis.readFully(fileLength, 0, fileLength.length);
OutputStream os = socket.getOutputStream();
//Sending size of file.
DataOutputStream dos = new DataOutputStream(os);
dos.writeLong(fileLength.length);
dos.write(fileLength, 0, fileLength.length);
dos.flush();
socket.close();
答案 0 :(得分:7)
它为您提供OutOfMemoryError
,因为您在发送之前尝试将整个文件读入内存。这是完全100%完全没必要的。只需读取和写入块,就像在接收代码中一样。
答案 1 :(得分:4)
问题是你试图将整个文件一次加载到内存中(通过readFully
),这超出了你的堆空间(我认为默认值是256mb)。
您有两种选择:
对于选项一,您可以尝试以下方式:
DataInputStream in = new DataInputStream(new FileInputStream("file.txt"));
byte[] arr = new byte[1024];
try {
int len = 0;
while((len = in.read(arr)) != -1)
{
// send the first len bytes of arr over socket.
}
} catch(IOException ex) {
ex.printStackTrace();
}
答案 2 :(得分:2)
OutOfMemoryError
。您将整个文件加载到RAM中。默认堆大小是物理内存大小的1/4或1GB,因此您的程序达到了限制(您可能有2GB RAM,因此堆大小为512MB)。
您应该以块(例如10MB)读取文件,因此您将无法达到堆大小限制,并且可以在出现某些错误时重新发送块,而不是重新发送整个文件。你甚至可以在不同的线程中读取块,所以当你发送1块时,你可以加载第二块,当你发送第一块时,你可以立即开始发送第二块。
答案 3 :(得分:1)
问题是在您的客户端中,您为整个文件创建了一个字节数组。
byte[] fileLength = new byte[(int) file.length()]; //potentially huge buffer allocated here
您应该在服务器端执行相同的操作,并将块中的文件块读入固定大小的缓冲区。
答案 4 :(得分:0)
就像你在服务器端使用缓冲区一样发送数据,使用applet / client中的缓冲区来读取它。如果您要传输大文件,则在使用readFully()
时显然会耗尽内存。此方法仅适用于您知道数据 真的 小的情况。