这是用于接收文件的服务器代码
public void receive(){
try {
DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
//read the number of files from the client
int number = dis.readInt();
ArrayList<File>files = new ArrayList<File>(number);
System.out.println("Number of Files to be received: " +number);
//read file names, add files to arraylist
for(int i = 0; i< number;i++){
File file = new File(dis.readUTF());
files.add(file);
}
int n = 0;
byte[]buf = new byte[4092];
//outer loop, executes one for each file
for(int i = 0; i < files.size();i++){
System.out.println("Receiving file: " + files.get(i).getName());
//create a new fileoutputstream for each new file
FileOutputStream fos = new FileOutputStream("C:\users\tom5\desktop\salestools\" +files.get(i).getName());
//read file
while((n = dis.read(buf)) != -1){
fos.write(buf,0,n);
fos.flush();
}
fos.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
这是用于发送文件的客户代码
public void send(ArrayList<File>files){
try {
DataInputStream dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
System.out.println(files.size());
//write the number of files to the server
dos.writeInt(files.size());
dos.flush();
//write file names
for(int i = 0 ; i < files.size();i++){
dos.writeUTF(files.get(i).getName());
dos.flush();
}
//buffer for file writing, to declare inside or outside loop?
int n = 0;
byte[]buf = new byte[4092];
//outer loop, executes one for each file
for(int i =0; i < files.size(); i++){
System.out.println(files.get(i).getName());
//create new fileinputstream for each file
FileInputStream fis = new FileInputStream(files.get(i));
//write file to dos
while((n =fis.read(buf)) != -1){
dos.write(buf,0,n);
dos.flush();
}
//should i close the dataoutputstream here and make a new one each time?
}
//or is this good?
dos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#1 楼
您正在读取套接字,直到read()
返回-1。这是流终止条件(EOS)。当对等方关闭连接时,会发生EOS。当完成一个文件的写入时,不是这样。您需要在每个文件之前发送文件大小。您已经在文件计数方面做了类似的事情。然后,确保已读取该文件的字节数:
String filename = dis.readUTF();
long fileSize = dis.readLong();
FileOutputStream fos = new FileOutputStream(filename);
while (fileSize > 0 && (n = dis.read(buf, 0, (int)Math.min(buf.length, fileSize))) != -1)
{
fos.write(buf,0,n);
fileSize -= n;
}
fos.close();
您可以将所有这些内容封装在一个循环中,该循环在
readUTF()
引发EOFException
时终止。相反,在发送数据之前,您当然必须在发送者处调用writeUTF(filename)
和writeLong(filesize)
。评论
shutdownOutput也不能用于表示EOF吗?
–龟头
2012年4月29日9:57
@ user384706是的。每个连接一次。因此,您只能发送一个文件。
–user207421
2012年4月29日在10:07
这样做很完美,我对n = dis.read(buf,0,Math.min)部分感到困惑,math.min是否确定文件大小是否小于缓冲区大小?如果是这样,它将仅使用file.length仅部分填充缓冲区?
– Tom 5
2012年4月30日14:41在
@Tom Math.min()用于正确处理最后一个缓冲区。您不能假定文件大小是缓冲区长度的倍数。
–user207421
2012年4月30日23:31
@FadlyDzil这不是编码服务。我已经提供了所有必需的代码。我希望任何有能力的程序员都能将我的其他言论变成可行的代码。
–user207421
19年4月28日在6:59
#2 楼
我是这样做的,它工作正常,可以看看:发送
byte[] done = new byte[3];
String str = "done"; //randomly anything
done = str.getBytes();
for (int i = 0; i < files.size(); i++) {
System.out.println(files.get(i).getName());
FileInputStream fis = new FileInputStream(files.get(i));
while ((n = fis.read(buf)) != -1) {
dos.write(buf, 0, n);
System.out.println(n);
dos.flush();
}
//should i close the dataoutputstream here and make a new one each time?
dos.write(done, 0, 3);
dos.flush();
}
//or is this good?
dos.close();
接收
for (int i = 0; i < files.size(); i++) {
System.out.println("Receiving file: " + files.get(i).getName());
//create a new fileoutputstream for each new file
fos = new FileOutputStream("C:\users\tom5\desktop\salestools\" + files.get(i).getName());
//read file
while ((n = dis.read(buf)) != -1 && n != 3) {
fos.write(buf, 0, n);
fos.flush();
}
fos.close();
}
评论
由于您的问题,我学到了一些新知识,您在每次文件传输后都要求关闭DataOutputStream,它实际上关闭了基础流,因此套接字已关闭。 Close()-关闭此输出流并释放与该流关联的所有系统资源。 Javadocs。
– Nikhar
2012年4月29日在16:16
嗯,我现在要发送文件大小并将它们存储在一个int数组中。我将其添加到服务器的while循环中,while((n = dis.read(buf))!= -1 && bytesRead
– Tom 5
2012年4月30日13:27
好的,我也尝试过,但是丢失/获得了几个字节。只需检查最后传输的文件,它会丢失几个字节吗?
– Nikhar
2012年4月30日13:56
哦,例如,接收5个文件,有时它将接收前3个迭代中的所有字节,而最后2个文件将为0字节,有时它将接收第4次迭代中的字节。相当随机
– Tom 5
2012年4月30日15:18
虽然,请阅读上面的文章,其中将Math.min添加到while((n = dis.read(buf,0,Math.min(n,FileSizes [i])))。这完全解决了问题,但扰乱了我的大脑正在进行中
– Tom 5
2012年4月30日15:20在
#3 楼
我已经创建了服务器和客户端。他们正在建立连接,并且该服务器之后每秒发送1MB文本文件。服务器和客户端代码如下。我经过长时间测试,发现没有数据丢失。我已经修改了上面回答的内容。服务器代码:
package com.dd.server;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
public class Server {
public static void main(String[] args) throws InterruptedException {
try {
byte[] done = new byte[3];
String str = "done"; //randomly anything
done = str.getBytes();
ServerSocket ss = new ServerSocket(5000);
Socket socket = ss.accept();
byte[] mybytearray = new byte[4096];
OutputStream os = socket.getOutputStream();
TimeUnit.SECONDS.sleep(5);
while(true) {
DataOutputStream dos = new DataOutputStream(os);
File myFile= new File("I:\MY-LEARNINGS\JAVA\Workspace\server\src\com\dd\server\gistfile1.txt");
dos.writeUTF(myFile.getName());
dos.writeLong(myFile.length());
FileInputStream fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
int read;
System.out.println("---------File Writing started----------");
int count = 0;
while((read = dis.read(mybytearray)) != -1){
dos.write(mybytearray, 0, read);
dos.flush();
++count;
System.out.println("Writing sub component of file. Step : "+count);
}
System.out.println("---------File Writing ended----------");
System.out.println("Flushing data DONE command sent.");
dis.close();
bis.close();
fis.close();
TimeUnit.SECONDS.sleep(1);
System.out.println("File transfer has been completed.");
dos.write(done, 0, 3);
dos.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package clientcom.dd.clent;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
try {
Socket socket = new Socket("127.0.0.1", 5000);
InputStream in = socket.getInputStream();
DataInputStream dis = new DataInputStream(in);
while(true) {
FileOutputStream fos =
new FileOutputStream("I:\MY-LEARNINGS\JAVA\Workspace\client\"+System.currentTimeMillis()+"-data.txt");
int read = 0;
byte[] mybytearray = new byte[4096];
while ((read = dis.read(mybytearray)) != -1 && read != 3) {
fos.write(mybytearray, 0, read);
fos.flush();
}
fos.close();
//System.out.println("The value of read : "+read);
// System.out.println("File has been received successfully.");
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
评论
尝试自学Java,第一次做一些简单的项目就可以与io一起玩。我有一种感觉,我的dos.write(buf,0,n)及其接收伙伴只是继续读写,因此所有数据都被写入了第一个文件?当第一个文件已完全写入时,我是否需要添加控件以发出信号?嗯,仍然有同样的问题,所有数据都被写入第一个文件,不知道我在做什么错。
另一种选择是在“标题”中写入每个文件的大小以及文件名。然后您的服务器端代码可以知道何时停止写入每个文件,并开始下一个文件。