简体   繁体   中英

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).

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:

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?

Thank you.

Create a new instance of DataOutputStream and DataInputStream as shown below.

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

Anything over the network is 1s and 0s ie bytes. 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.

On the client side, read all the bytes from socket (using BufferedReader in practical projects) and write them to disk. You have to make sure both server and client are using the same encoding.

Use BufferedInputStream and BufferedOutputStream instead of DataXXXStream.

This will work for any file type - 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. In order to do that, we use a FileInputStream wrapped in a BufferedInputStream .

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. 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. We use the same Util.copy() method to actually copy the bytes from one stream to the other.

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. 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. See java.nio.file.Files

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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