java 使用 FileInputStream/ObjectOutputStream 发送大文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10819516/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sending big file using FileInputStream/ObjectOutputStream
提问by Ozzy
I need help on my homework, any help will be much appreciated. I can send small files without a problem. But when i try to send let's say a 1GB file byte array sends OutOfMemoryError so i need a better solution to send file from server to client. How can i improve this code and send big files, please help me.
我的作业需要帮助,任何帮助将不胜感激。我可以毫无问题地发送小文件。但是,当我尝试发送时,假设 1GB 文件字节数组发送 OutOfMemoryError,因此我需要一个更好的解决方案来将文件从服务器发送到客户端。我该如何改进此代码并发送大文件,请帮助我。
Server Code:
服务器代码:
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);
Client Code:
客户代码:
ois = new ObjectInputStream(sock.getInputStream());
byte[] file = (byte[]) ois.readObject();
fos = new FileOutputStream(file);
fos.write(file);
采纳答案by Ozzy
Here's how I solved it:
这是我解决它的方法:
Client Code:
客户代码:
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);}
Server Code:
服务器代码:
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);
回答by Hyman
Just split the array to smaller chunks so that you don't need to allocate any big array.
只需将数组拆分为较小的块,这样您就不需要分配任何大数组。
For example you could split the array into 16Kb chunks, eg new byte[16384]
and send them one by one. On the receiving side you would have to wait until a chunk can be fully read and then store them somewhere and start with next chunk.
例如,您可以将数组拆分为 16Kb 的块,new byte[16384]
然后将它们一一发送。在接收方,您必须等到可以完全读取一个块,然后将它们存储在某处并从下一个块开始。
But if you are not able to allocate a whole array of the size you need on server side you won't be able to store all the data that you are going to receive anyway.
但是,如果您无法在服务器端分配所需大小的整个数组,则无论如何都无法存储将要接收的所有数据。
You could also compress the data before sending it to save bandwidth (and time), take a look at ZipOutputStream
and ZipInputStream
.
您还可以在发送数据之前对其进行压缩以节省带宽(和时间),请查看ZipOutputStream
和ZipInputStream
。
回答by ErikFWinter
Don't read the whole file into memory, use a small buffer and write while you are reading the file:
不要将整个文件读入内存,在读取文件时使用一个小缓冲区并写入:
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):
}
Use Buffered* to optimize the writing and reading from Streams
使用 Buffered* 优化 Streams 的读写
回答by jtahlborn
Depending on whether or not you have to write the code yourself, there are existing libraries which solve this problem, e.g. rmiio. If you are not using RMI, just plain java serialization, you can use the DirectRemoteInputStream, which is kind of like a Serializable InputStream. (this library also has support for things like auto-magically compressing the data).
根据您是否必须自己编写代码,现有的库可以解决这个问题,例如rmiio。如果你不使用 RMI,只是简单的 java 序列化,你可以使用DirectRemoteInputStream,它有点像一个 Serializable InputStream。(这个库还支持诸如自动神奇地压缩数据之类的东西)。
Actually, if you are onlysending file data, you would be better off ditching the Object streams and use DataInput/DataOutput streams. first write an integer indicating the file length, then copy the bytes directly to the stream. on the receiving side, read the integer file length, then read exactly that many bytes.
实际上,如果您只发送文件数据,最好放弃 Object 流并使用 DataInput/DataOutput 流。首先写入一个表示文件长度的整数,然后将字节直接复制到流中。在接收端,读取整数文件长度,然后准确读取那么多字节。
when you copy the data between streams, use a small, fixed size byte[] to move chunks of data between the input and output streams in a loop. there are numerous examples of how to do this correctly available online (e.g. @ErikFWinter's answer).
在流之间复制数据时,使用一个小的、固定大小的 byte[] 在循环中的输入和输出流之间移动数据块。网上有很多关于如何正确执行此操作的示例(例如@ErikFWinter 的回答)。