Svyatoslav Nenashev Asked:2020-09-12 14:49:07 +0800 CST2020-09-12 14:49:07 +0800 CST 2020-09-12 14:49:07 +0800 CST 如何在套接字上发送文件名? 772 该应用程序将传输许多文件,对我来说,使用名称传输它们很重要。为此,您每次都需要使用文件名发送一条消息,或者是否有可能以不同的方式进行? java 2 个回答 Voted Best Answer Sergey Gornostaev 2020-09-12T15:06:29+08:002020-09-12T15:06:29+08:00 您发送的第一个字节是文件名的长度,接下来的 4 个字节是文件的长度,然后是文件名的字节,然后是文件本身的字节。或者,为了不打扰数据转换,您可以稍微扩展字段: 服务器.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(); } } } 客户端.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; } } } DaysLikeThis 2020-09-12T16:33:09+08:002020-09-12T16:33:09+08:00 有几种方法可以解决您的问题: 序列化。使用内置的序列化(Java Serialization API),或流行的库之一。也就是说,你序列化一个对象,在接收端传递和反序列化它。 使用您自己的通信协议。例如,在建立连接后,客户端发送一个文件名,接收来自服务器的确认,然后发送文件的内容,并再次收到文件已被接收的确认。 在一个请求中发送文件名及其内容,然后您需要组织数据传输格式,如本答案中所述
您发送的第一个字节是文件名的长度,接下来的 4 个字节是文件的长度,然后是文件名的字节,然后是文件本身的字节。或者,为了不打扰数据转换,您可以稍微扩展字段:
服务器.java
客户端.java
有几种方法可以解决您的问题:
序列化。使用内置的序列化(Java Serialization API),或流行的库之一。也就是说,你序列化一个对象,在接收端传递和反序列化它。
使用您自己的通信协议。例如,在建立连接后,客户端发送一个文件名,接收来自服务器的确认,然后发送文件的内容,并再次收到文件已被接收的确认。
在一个请求中发送文件名及其内容,然后您需要组织数据传输格式,如本答案中所述