#java #android
#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. Пытаюсь самостоятельно освоить Java, просто делаю несколько простых проектов, чтобы впервые поиграть с io. У меня такое чувство, что мой dos.write (buf, 0, n) и его принимающий партнер просто продолжают чтение и запись, таким образом, все данные записываются в первый файл? Нужно ли добавлять элемент управления, чтобы сигнализировать, когда первый файл был записан полностью?
2. Хм, все та же проблема, все данные записываются в первый файл, не знаю, что я делаю не так.
3. другим вариантом было бы записать размеры каждого файла вместе с именами файлов в ‘header’. Тогда ваш серверный код может знать, когда следует прекратить запись в каждый файл и запустить следующий.
Ответ №1:
Вы читаете сокет до тех пор, пока read()
не вернет значение -1. Это условие завершения потока (EOS). EOS происходит, когда одноранговый узел закрывает соединение. Не тогда, когда он заканчивает запись одного файла.
Вам нужно отправить размер файла перед каждым файлом. Вы уже делаете аналогичную вещь с количеством файлов. Затем убедитесь, что вы прочитали именно столько байтов для этого файла:
String filename = dis.readUTF();
long fileSize = dis.readLong();
FileOutputStream fos = new FileOutputStream(filename);
while (fileSize > 0 amp;amp; (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)
у отправителя перед отправкой данных.
Комментарии:
1. Не может
shutdownOutput
также использоваться для указанияEOF
?2. @user384706 Да. Один раз за соединение. Таким образом, вы могли отправить только один файл.
3. Это сработало отлично, меня смущает часть n = dis.read (buf, 0, Math.min), определяет ли math.min, меньше ли размер файла размера буфера? и если это так, это лишь частично заполнит буфер только файлом. длина?
4. @Tom
Math.min()
заключается в правильной обработке последнего буфера. Вы не можете предполагать, что размер файла кратен длине вашего буфера.5. @FadlyDzil Это не служба кодирования. Я уже предоставил весь необходимый код. Я ожидаю, что любой компетентный программист сможет превратить другие мои замечания в рабочий код.
Ответ №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 amp;amp; n != 3) {
fos.write(buf, 0, n);
fos.flush();
}
fos.close();
}
Комментарии:
1. благодаря вашей проблеме я узнал кое-что новое: то, что вы просили закрыть
DataOutputStream
после каждой передачи файла, фактически закрывает базовый поток, и, таким образом, сокет как бы закрыт.Close()-Closes this output stream and releases any system resources associated with the stream.
Javadocs.2. хммм, сейчас я отправляю размер файла и сохраняю их в массиве int. Я добавил это на свой сервер в цикле while, while((n = dis.read(buf)) != -1 amp;amp; bytesRead < Размер файла));
3. хорошо, я тоже пробовал это, но произошла потеря / усиление нескольких байтов. Просто проверьте последний файл, который был передан, он теряет несколько байтов?
4. о да, например, при получении 5 файлов, иногда он получит все байты за первые 3 итерации, а 2 последних файла будут равны 0 байтам, иногда он будет получать байты на 4-й итерации. Было довольно случайным
5. Хотя, прочитайте сообщение выше, где Math.min был добавлен в while((n = dis.read(buf,0,Math.min(n, размер файла [i])). Это полностью устранило проблему, но в процессе запутало мой мозг
Ответ №3:
Я создал сервер и клиент. Они устанавливают соединение, и после этого сервер отправляет текстовый файл размером 1 МБ каждую секунду. Ниже приведен код сервера и клиента. Я протестировал long duration и увидел, что данные не потеряны. Я немного изменил приведенный выше ответ.
СЕРВЕРНЫЙ КОД:
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 amp;amp; 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();
}
}
}