Передача нескольких файлов Java через сокет
Хорошо, при попытке передать указанный каталог файлов через сокет удалите объекты каталога из arraylist, чтобы остались только файлы, и передайте их 1 к 1 через тот же сокет. Список массивов здесь заполнен ТОЛЬКО файлами, никаких каталогов. Вот код приема и отправки для клиента и сервера соответственно. Код работает нормально, без ошибок, за исключением того, что ВСЕ данные записываются в первый файл. Последующие файлы создаются в папке сервера, но их размер составляет 0 байт. Мы будем очень признательны за любой ввод.
ЭТО СЕРВЕРНЫЙ КОД ДЛЯ ПОЛУЧЕНИЯ ФАЙЛОВ
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)
отправителю перед отправкой данных.
Ответ 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();
}
Ответ 3
Я создал сервер и клиент. Они устанавливают соединение, и после этого сервер отправляет текстовый файл размером 1 МБ каждую секунду. Код сервера и клиента приведен ниже. Я провел длительное тестирование и увидел, что данные не потеряны. Я немного изменил приведенный выше ответ.
СЕРВЕРНЫЙ КОД:
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();
}
}
}