Страницы

Поиск по вопросам

среда, 4 декабря 2019 г.

Как передать название файла по сокету?

#java #сокет


Приложение будет передавать множество файлов, и мне важно, что бы они были переданы
с названиями. Для этого нужно отправлять каждый раз сообщение с названием файла или
это как то можно сделать иначе?
    


Ответы

Ответ 1



Первым байтом отправляете длину имени файла, следующие 4 байта - длина файла, следом байты имени файла, а потом байты самого файла. Или, чтобы не заморачиваться с конвертацией данных, можно поля чуточку расширить: Server.java package com.example; import java.io.File; import java.io.FileInputStream; import java.io.OutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.net.ServerSocket; import java.net.Socket; public class Server { private static int PORT = 2121; private static String FOLDER = "./files"; public static void main(String[] args) { File sourceDir = new File(FOLDER); try (ServerSocket listener = new ServerSocket(PORT)) { while (true) { try (Socket socket = listener.accept(); OutputStream out = socket.getOutputStream()) { for (String fileName : sourceDir.list()) { // Преобразовываем строку, содержащую имя файла, // в массив байт byte[] name = fileName.getBytes("utf-8"); // Отправляем длину этого массива out.write(name.length); // Отправляем байты имени out.write(name); File file = new File(FOLDER + "/" + fileName); // Получаем размер файла long fileSize = file.length(); // Конвертируем его в массив байт ByteBuffer buf = ByteBuffer.allocate(Long.BYTES); buf.putLong(fileSize); // И отправляем out.write(buf.array()); try (FileInputStream in = new FileInputStream(file)) { // Читаем файл блоками по килобайту byte[] data = new byte[1024]; int read; while ((read = in.read(data)) != -1) { // И отправляем в сокет out.write(data); } } catch(IOException exc) { exc.printStackTrace(); } } } catch(IOException exc) { exc.printStackTrace(); } } } catch(IOException exc) { exc.printStackTrace(); } } } Client.java package com.example; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.net.Socket; public class Client { private static int PORT = 2121; private static String HOST = "localhost"; private static String FOLDER = "./files"; public static void main(String[] args) { try (Socket s = new Socket(HOST, PORT); InputStream in = s.getInputStream()) { // Читаем размер имени int nameSize; while((nameSize = in.read()) != -1) { // Читаем само имя byte[] name = new byte[nameSize + 1]; in.read(name, 0, nameSize); // Преобразовываем обратно в строку String fileName = new String(name, "utf-8").trim(); System.out.println(fileName); File file = new File(FOLDER + "/" + fileName); try (FileOutputStream out = new FileOutputStream(file)) { // Читаем размер файл byte[] fileSizeBuf = new byte[8]; in.read(fileSizeBuf, 0, 8); // Преобразовываем в long ByteBuffer buf = ByteBuffer.allocate(Long.BYTES); buf.put(fileSizeBuf); buf.flip(); long fileSize = buf.getLong(); // Читаем содержимое файла блоками по килобайту int read = 0; byte[] data = new byte[1024]; while (read < fileSize) { read += in.read(data); // И пишем в файл out.write(data); } } catch(IOException exc) { exc.printStackTrace(); } } } catch(IOException exc) { exc.printStackTrace(); return; } } }

Ответ 2



Есть несколько подходов к решению Вашей проблемы: Сериализация. Использовать встроенную сериализацию (Java Serialization API), либо одну из популярных библиотек. То есть вы сериализуете объект, передаете и десериализуете его на приемной стороне. Использовать свой протокол обмена данных. Например, после установления соединения, клиент передает имя файла, получает подтверждение от сервера, затем передает содержимое файла и снова получает подтверждение о получении файла. Посылать имя файла и его содержимое одним запросом, тогда необходимо организовывать формат передачи данных, как уже было описано в этом ответе

Комментариев нет:

Отправить комментарий