我的作业需要帮助,非常感谢任何帮助。我可以毫无问题地发送小文件。但是当我尝试发送时,假设一个1GB的文件字节数组发送OutOfMemoryError,所以我需要一个更好的解决方案来将文件从服务器发送到客户端。如何改进此代码并发送大文件,请帮助我。
服务器代码:
FileInputStream fis = new FileInputStream(file);
byte[] fileByte = new byte[fis.available()]; //This causes the problem.
bytesRead = fis.read(fileByte);
oos = new ObjectOutputStream(sock.getOutputStream());
oos.writeObject(fileByte);
客户代码:
ois = new ObjectInputStream(sock.getInputStream());
byte[] file = (byte[]) ois.readObject();
fos = new FileOutputStream(file);
fos.write(file);
答案 0 :(得分:4)
只需将数组拆分为较小的块,这样就不需要分配任何大数组了。
例如,您可以将数组拆分为16Kb块,例如new byte[16384]
并逐个发送。在接收方,你必须等到一个块可以被完全读取,然后将它们存储在某个地方并从下一个块开始。
但如果您无法在服务器端分配所需大小的整个数组,则无法存储您将要接收的所有数据。
您还可以在发送数据之前压缩数据以节省带宽(和时间),请查看ZipOutputStream
和ZipInputStream
。
答案 1 :(得分:3)
不要将整个文件读入内存,使用小缓冲区并在读取文件时写入:
BufferedOutputStream bos = new BufferedOutputStream(sock.getOutputStream())
File file = new File("asd");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] buffer = new byte[1024*1024*10];
int n = -1;
while((n = bis.read(buffer))!=-1) {
bos.write(buffer,0,n):
}
使用Buffered *优化Streams的写入和读取
答案 2 :(得分:1)
以下是我如何解决它:
客户代码:
bis=new BufferedInputStream(sock.getInputStream());
fos = new FileOutputStream(file);
int n;
byte[] buffer = new byte[8192];
while ((n = bis.read(buffer)) > 0){
fos.write(buffer, 0, n);}
服务器代码:
bos= new BufferedOutputStream(sock.getOutputStream());
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
int n=-1;
byte[] buffer = new byte[8192];
while((n = bis.read(buffer))>-1)
bos.write(buffer,0,n);
答案 3 :(得分:0)
根据您是否必须自己编写代码,现有的库可以解决此问题,例如: rmiio。如果你没有使用RMI,只是简单的java序列化,你可以使用DirectRemoteInputStream,它有点像Serializable InputStream。 (该库还支持自动神奇地压缩数据等内容。)
实际上,如果您仅发送文件数据,那么最好放弃对象流并使用DataInput / DataOutput流。首先写一个表示文件长度的整数,然后将字节直接复制到流中。在接收端,读取整数文件长度,然后读取那么多字节。
在流之间复制数据时,使用一个小的固定大小的byte []在循环中在输入和输出流之间移动数据块。有很多例子说明如何在网上正确地提供这些服务(例如@ ErikFWinter的回答)。