简体   繁体   English

Java TCP-使用DataOutputStream发送文件

[英]Java TCP - Sending a file using DataOutputStream

Hi and thanks in advance. 嗨,谢谢你。

So currently, I am trying to have my TCP program read a file from a directory (this is server side), and then send that file over to the socket that requested it (the client). 因此,当前,我正在尝试让我的TCP程序从目录(这是服务器端)读取文件,然后将该文件发送到请求该文件的套接字(客户端)。

Here is my code: 这是我的代码:

Server side: 服务器端:

File FileList = new File(".....filepath....");
Scanner scan = new Scanner(FileList);

//idToFile just searching for the name of the file the client asked for
String TheName = idToFile(Integer.toString(result));

//Opens the chosen file such as an image to be used     
File myImageFile = new File("....filepath...." + TheName);

//sendResponse is a function with a writeUTF (but only works for strings)
sendResponse("#OK");
sendResponse(TheName);
sendResponse(Long.toString(myImageFile.length()));

//This line causes the error and says that it expected a string and not a file          
output.writeUTF(myImageFile);


private void sendResponse(String response)
    {
        try 
        {
            output.writeUTF(response);
        } 
        catch (IOException ex) 
        {
            ex.printStackTrace();
        }
    }

Client side: 客户端:

ClientHandler client = new ClientHandler();


//getResponse just catches the written strings, but it can't work with a file either
String TheMessage = client.getResponse();
String Name = client.getResponse();
long FileSize = Long.parseLong(client.getResponse());

Here is the code for ClientHandler: 这是ClientHandler的代码:

public class ClientHandler 
{
    private static int port = 2016;

    private DataInputStream input;
    private DataOutputStream output;

    private Socket cSocket; 


    public ClientHandler()
    {
        cSocket = null;

        try
        {
            cSocket = new Socket("localhost", port); //connecting to the server 
            System.out.println("Client is connected on port " + port);

            output = new DataOutputStream(cSocket.getOutputStream());
            input = new DataInputStream(cSocket.getInputStream());
        }
        catch(IOException ex)
        {
            ex.printStackTrace();
        }
    }

    public void sendMessage(String message) //checking if the message is sent
    {
        try
        {
            output.writeUTF(message);
            output.flush();
            System.out.println("Message sent to the server");
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        }
    }

    public String getResponse()
    {
        String msg = "";
        try
        {
              msg = input.readUTF();
        }
        catch(IOException ex)
        {
            ex.printStackTrace(); 
        }
        return msg;
    }

}

So how can I use a DataOutputStream to send any kind of file from my server to my client, and how can my client catch that file using DataInputStream and save it to disk? 那么,如何使用DataOutputStream将任何类型的文件从服务器发送到客户端,以及我的客户端如何使用DataInputStream捕获该文件并将其保存到磁盘?

Thank you. 谢谢。

Create a new instance of DataOutputStream and DataInputStream as shown below. 如下所示创建DataOutputStreamDataInputStream的新实例。

DataOutputStream socketOut = new DataOutputStream(socketObject.getOutputStream());
DataInputStream  socketIn  = new DataInputStream(socketObject.getInputStream());

For sample code, checkout the sample class shown in this lecture notes. 有关示例代码,请签出本讲义中显示的示例类

For quick reference, here are the snippets from the sample class 为了快速参考,以下是示例类的摘录

DataInputStream streamIn = new 
              DataInputStream(new 
              BufferedInputStream(client.getInputStream()));
String incomingDataLine = streamIn.readLine();
...
...
DataOutputStream socketOut = new DataOutputStream(client.getOutputStream());
socketOut.writeBytes(line + '\n');

========= Edit 1: After reading your comments =========编辑1:阅读评论后

Anything over the network is 1s and 0s ie bytes. 网络上的任何内容都是1和0,即字节。 Let's say you want to transfer an image from one server to another then the recommended way is for the server to read the file contents as bytes java.nio.Files.readAllBytes() and write this to the socket. 假设您要将映像从一台服务器传输到另一台服务器,那么推荐的方法是让服务器读取文件内容(以字节java.nio.Files.readAllBytes()并将其写入套接字)。

On the client side, read all the bytes from socket (using BufferedReader in practical projects) and write them to disk. 在客户端,从套接字读取所有字节(在实际项目中使用BufferedReader)并将其写入磁盘。 You have to make sure both server and client are using the same encoding. 您必须确保服务器和客户端都使用相同的编码。

Use BufferedInputStream and BufferedOutputStream instead of DataXXXStream. 使用BufferedInputStream和BufferedOutputStream代替DataXXXStream。

This will work for any file type - mp3, mp4, jpeg, png, acc, txt, java. 这将适用于任何文件类型-mp3,mp4,jpeg,png,acc,txt,java。 To have it usable in client system, make sure to create a file with the correct extension. 要使其在客户端系统中可用,请确保创建具有正确扩展名的文件。

Here as an example a simple server, which sends a binary file to each client without further interaction. 这里以一个简单的服务器为例,该服务器将二进制文件发送到每个客户端,而无需进一步的交互。

The socket provides the output stream to write bytes to the client. 套接字提供输出流以将字节写入客户端。 We have a file "picin.jpg" we want to send, so we need to write every byte of this file to the socket's output stream. 我们有一个要发送的文件“ picin.jpg”,因此我们需要将此文件的每个字节写入套接字的输出流。 In order to do that, we use a FileInputStream wrapped in a BufferedInputStream . 为了做到这一点,我们使用包裹在BufferedInputStreamFileInputStream

package networking;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {

  public static void main(String[] args) {
    try {
      ServerSocket ss = new ServerSocket();
      ss.bind(new InetSocketAddress("localhost", 4711));
      for(;;) {
        Socket sock = ss.accept();
        System.out.println("Connected to " + sock.getInetAddress());
        try (
          InputStream in = new BufferedInputStream(new FileInputStream("picin.jpg"));
          OutputStream out = sock.getOutputStream();
        ) 
        {
          int bytesSent = Util.copy(in, out);
          System.out.println(String.format("%d bytes sent.", bytesSent));
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

I extracted the copy method to a util class, because we need the exact same in the client. 我将copy方法提取到util类中,因为我们需要客户端中完全相同的方法。 We use a small byte array as a buffer and copy one chunk after another from one stream to the other. 我们使用一个小字节数组作为缓冲区,然后将一个块又一个块从一个流复制到另一个流。

package networking;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class Util {
  public static int copy(InputStream in, OutputStream out) throws IOException {
    byte[] buf = new byte[2048];
    int bytesRead = 0;
    int totalBytes = 0;
    while((bytesRead = in.read(buf)) != -1) {
      totalBytes += bytesRead;
      out.write(buf, 0, bytesRead);
    }
    return totalBytes;
  }

}

The client opens a connection to the server and write the received bytes to a file. 客户端打开与服务器的连接,并将接收到的字节写入文件。 The socket provides the input stream with the bytes coming from the server. 套接字为输入流提供来自服务器的字节。 We use a FileOutputStream wrapped in a BufferedOutputStream to write to the file. 我们使用包裹在BufferedOutputStreamFileOutputStream写入文件。 We use the same Util.copy() method to actually copy the bytes from one stream to the other. 我们使用相同的Util.copy()方法将字节实际上从一个流复制到另一个流。

package networking;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class Client {

  public static void main(String[] args) {
    try {
      Socket sock = new Socket(InetAddress.getByName("localhost"), 4711);
      try(
        InputStream in = sock.getInputStream();
        OutputStream out = new BufferedOutputStream(new FileOutputStream("picout.jpg"))
      )
      {
        System.out.println("Connected to " + sock.getRemoteSocketAddress());
        int bytesCopied = Util.copy(in, out);
        System.out.println(String.format("%d bytes received", bytesCopied));
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

}

Note: The streams are closed automatically by the try-with-ressources statement. 注意:流通过try-with-ressources语句自动关闭。 The sockets are closed while the corresponding streams are closed. 关闭套接字,同时关闭相应的流。

Java 8 includes some convenience methods to copy bytes from a file to an output stream or from an input stream to a file. Java 8包含一些方便的方法,可将字节从文件复制到输出流或从输入流复制到文件。 See java.nio.file.Files 参见java.nio.file.Files

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM