我正在尝试通过套接字发送大文件。该程序适用于小文件(如html页面或pdf),但当我发送超过3/4 mb的文件时,输出总是被破坏(用文本编辑器查看它,我注意到最后几行总是丢失)。
这是服务器的代码:
BufferedInputStream in = null;
FileOutputStream fout = null;
try {
server = new ServerSocket(port);
sock = server.accept();
in = new BufferedInputStream(sock.getInputStream());
setPerc(0);
received = 0;
int incByte = -1;
fout = new FileOutputStream(path+name, true);
long size = length;
do{
int buffSize;
if(size >= 4096){
buffSize = 4096;
}else{
buffSize = 1;
}
byte[] o = new byte[buffSize];
incByte = in.read(o, 0, buffSize);
fout.write(o);
received+=buffSize;
setPerc(calcPerc(received, length));
size -= buffSize;
//d("BYTE LETTI => "+incByte);
}while(size > 0);
server.close();
} catch (IOException e) {
e("Errore nella ricezione file: "+e);
}finally{
try {
fout.flush();
fout.close();
in.close();
} catch (IOException e) {
e("ERRORE INCOMINGFILE");
}
}
pr.release(port);
这是客户的代码:
FileInputStream fin = null;
BufferedOutputStream out = null;
try {
sock = new Socket(host, port);
fin = new FileInputStream(file);
out = new BufferedOutputStream(sock.getOutputStream());
long size = file.length();
int read = -1;
do{
int buffSize = 0;
if(size >= 4096){
buffSize = 4096;
}else{
buffSize = (int)size;
}
byte[] o = new byte[buffSize];
for(int i = 0; i<o.length;i++){
o[i] = (byte)0;
}
read = fin.read(o, 0, buffSize);
out.write(o);
size -= buffSize;
//d("BYTE LETTI DAL FILE => "+read);
}while(size > 0);
} catch (UnknownHostException e) {
} catch (IOException e) {
d("ERRORE NELL'INVIO DEL FILE: "+e);
e.printStackTrace();
}finally{
try {
out.flush();
out.close();
fin.close();
} catch (IOException e) {
d("Errore nella chiusura dei socket invio");
}
}
我认为这与缓冲区大小有关,但我无法弄清楚这里有什么问题。
答案 0 :(得分:3)
这是不正确的:
byte[] o = new byte[buffSize];
incByte = in.read(o, 0, buffSize);
fout.write(o);
您正在阅读最多 buffSize
字节,然后正确地写 buffSize
个字节。
你也在另一端做同样的事情。
从文件 1 读取时,你可以逃脱这一点,但是当你从套接字读取时,read
可能会给你一个部分填充的缓冲区,特别是如果写作结束不能始终保持在读取结束之前'因为你正在通过大转移锤击网络。
正确的方法是:
incByte = in.read(o, 0, buffSize);
fout.write(o, 0, incByte);
1 - 据观察,当您从本地文件中读取时,read
调用通常会为您提供所请求的所有字节数(取决于文件大小等)。因此,如果将buffSize
设置为文件的长度,则从本地文件读取时此代码可能会起作用。但这样做是个坏主意,因为您依赖的是Java或典型操作系统无法保证的行为。
答案 1 :(得分:0)
您可能遇到问题,例如这里。
read = fin.read(o, 0, buffSize);
out.write(o);
此处读取会为您提供实际读取的字节数。 在下一行,你应该只写出你读过的字节数。
换句话说,你不能指望文件的大小 你读的是你的缓冲区大小的倍数。
检查您的服务器代码是否存在同样的问题。
答案 2 :(得分:0)
在Java中复制流的正确方法如下:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
其中count
是int,
,而buffer
是byte[]
长度&gt;数组0,通常为8k。您不需要在循环内部分配字节数组,也不需要特定大小的字节数组。具体来说,分配与文件一样大的缓冲区完全浪费空间;它只适用于Integer.MAX_VALUE
字节的文件,并且不能扩展。
你需要保存'read()'返回的计数,并在'write()'方法中使用它,如上所示。