Java 使用FileInputStream/ObjectOutputStream发送大文件

Java 使用FileInputStream/ObjectOutputStream发送大文件,java,bytearray,inputstream,outputstream,Java,Bytearray,Inputstream,Outputstream,我的家庭作业需要帮助,任何帮助都将不胜感激。我可以毫无问题地发送小文件。但当我尝试发送时,比如说1GB文件字节数组发送OutOfMemoryError,所以我需要一个更好的解决方案将文件从服务器发送到客户端。如何改进此代码并发送大文件,请帮助我 服务器代码: FileInputStream fis = new FileInputStream(file); byte[] fileByte = new byte[fis.available()]; //This causes the

我的家庭作业需要帮助,任何帮助都将不胜感激。我可以毫无问题地发送小文件。但当我尝试发送时,比如说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);
 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);
客户端代码:

    ois = new ObjectInputStream(sock.getInputStream());
    byte[] file = (byte[]) ois.readObject();
    fos = new FileOutputStream(file);
    fos.write(file);
 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);}

只需将数组分割成更小的块,这样就不需要分配任何大数组

例如,您可以将数组拆分为16Kb的块,例如
新字节[16384]
,然后逐个发送它们。在接收端,您必须等待一个块被完全读取,然后将它们存储在某个地方,然后从下一个块开始

但是,如果您无法在服务器端分配所需大小的整个阵列,那么您将无法存储您将要接收的所有数据


您还可以在发送数据之前对其进行压缩,以节省带宽(和时间),查看并。

只需将阵列拆分为较小的块,这样就不需要分配任何大阵列

例如,您可以将数组拆分为16Kb的块,例如
新字节[16384]
,然后逐个发送它们。在接收端,您必须等待一个块被完全读取,然后将它们存储在某个地方,然后从下一个块开始

但是,如果您无法在服务器端分配所需大小的整个阵列,那么您将无法存储您将要接收的所有数据


您也可以在发送数据之前对其进行压缩,以节省带宽(和时间),查看和。

不要将整个文件读入内存,在读取文件时使用一个小缓冲区并进行写入:

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*优化流的写入和读取

不要将整个文件读取到内存中,在读取文件时使用一个小的缓冲区进行写入:

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*优化流的写入和读取

取决于您是否必须自己编写代码,现有库可以解决此问题,例如。如果不使用RMI,只使用普通java序列化,那么可以使用,这有点像可序列化的InputStream。(该库还支持自动神奇地压缩数据)

实际上,如果您只发送文件数据,那么最好放弃对象流并使用DataInput/DataOutput流。首先写入一个表示文件长度的整数,然后将字节直接复制到流中。在接收端,读取整数文件长度,然后精确读取那么多字节


在流之间复制数据时,请使用固定大小的小字节[]在循环中的输入流和输出流之间移动数据块。在线提供了许多关于如何正确执行此操作的示例(例如@ErikFWinter的答案)。

根据您是否必须自己编写代码,现有的库可以解决此问题,例如。如果不使用RMI,只使用普通java序列化,那么可以使用,这有点像可序列化的InputStream。(该库还支持自动神奇地压缩数据)

实际上,如果您只发送文件数据,那么最好放弃对象流并使用DataInput/DataOutput流。首先写入一个表示文件长度的整数,然后将字节直接复制到流中。在接收端,读取整数文件长度,然后精确读取那么多字节


在流之间复制数据时,请使用固定大小的小字节[]在循环中的输入流和输出流之间移动数据块。在线提供了许多正确执行此操作的示例(例如@ErikFWinter的答案)。

以下是我解决此问题的方法:

客户端代码:

    ois = new ObjectInputStream(sock.getInputStream());
    byte[] file = (byte[]) ois.readObject();
    fos = new FileOutputStream(file);
    fos.write(file);
 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);}
服务器代码:

    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);
 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);

我是这样解决的:

客户端代码:

    ois = new ObjectInputStream(sock.getInputStream());
    byte[] file = (byte[]) ois.readObject();
    fos = new FileOutputStream(file);
    fos.write(file);
 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);}
服务器代码:

    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);
 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);

“发送内存不足异常”在Java中没有这样的事情,DYM?如果是,请具体说明,如果不是,请解释(也特别说明)。顺便说一句,您的第一个代码似乎暗示输入文件始终包含序列化对象。这里是这样吗?哦,对不起,这是OutOfMemoryError,不例外。我不知道您的意思,如果文件包含序列化对象,服务器将发送客户端请求的任何文件。
ObjectOutputStream
ObjectInputStream
用于序列化对象。如果内容是“任何旧字节”,代码就不应该使用它们。好的,我会这样做,谢谢你,我是新来这里的。“发送内存不足异常”在Java中没有这样的事情,DYM?如果是,请具体说明,如果不是,请解释(也特别说明)。顺便说一句,您的第一个代码似乎暗示输入文件始终包含序列化对象。这里是这样吗?哦,对不起,这是OutOfMemoryError,不例外。我不知道您的意思,如果文件包含序列化对象,服务器将发送客户端请求的任何文件。
ObjectOutputStream
ObjectInputStream
用于序列化对象。如果内容是“任何旧字节”,则代码不应使用它们。好的,我将这样做,谢谢,我是新来的。非常感谢,我将尝试此方法。非常感谢,我将尝试此方法。我遵循此示例,在接收端的while循环中,我打印“编写文件…”。我看到的是,接收器最终处于无限循环中,永远不会完成接收。我可以看到它接收到的文件,文件大小最终达到它应该有多大,然后它停止了,但客户端从未停止思考它接收的数据。如果我关闭接收器并尝试打开文件,则文件已损坏。我遵循此示例,在接收端的while循环中,我打印“Writing file…”。我看到的是,接收器最终处于无限循环中,永远不会完成接收。我可以看到它收到的文件和f