0

I have the following code which transfers file via Sockets. How do I send the file name?

Socket socket = new Socket("localhost", port);//machine name, port number
File file = new File(fileName);
// Get the size of the file
long length = file.length();
if (length > Integer.MAX_VALUE) 
{
    System.out.println("File is too large.");
}
byte[] bytes = new byte[(int) length];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());

int count;

while ((count = bis.read(bytes)) > 0) 
{
    out.write(bytes, 0, count);
}

out.flush();
out.close();
fis.close();
bis.close();
socket.close();
5
  • how to send file name with file? If I'm correct use File.getName() Commented Mar 27, 2013 at 0:34
  • 3
    I think the OP is looking for a protocol definition so that the receiving end can know where to store the file. This requires End-of-record markers and the like - why not use a well-established protocol like FTP? Commented Mar 27, 2013 at 0:37
  • 1
    @RonDahlgren Because FTP is kind of terrible, overkill for this purpose, and I'm not sure the Java support for it is any good? For a simple file upload from sender A to a not necessarily filesystem-shaped receiver B, HTTP would work better. Commented Mar 27, 2013 at 0:44
  • With TCP socket you can basically send anything, it's not limited to certain classes / types. Think of every single objects / variable as a collection of bytes. Commented Mar 27, 2013 at 0:47
  • no I'm building a p2p network. When the file is send, the receiver has to know the name of the file, does not need to know where to store the file. It can store it anywhere. Commented Mar 27, 2013 at 1:22

3 Answers 3

6

You can invent your own protocol for your socket. If all you need is a filename and data, DataOutputStream.writeUTF is easiest:

BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
try (DataOutputStream d = new DataOutputStream(out)) {
    d.writeUTF(fileName);
    Files.copy(file.toPath(), d);
}

The peer must use the same protocol, of course:

BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
try (DataInputStream d = new DataInputStream(in)) {
    String fileName = d.readUTF();
    Files.copy(d, Paths.get(fileName));
}
Sign up to request clarification or add additional context in comments.

Comments

2

Use a character that can never be in a file name - such as a null (0x00, \0, whatever you want to call it). Then send a 64 bit integer that indicates how long, in bytes, the file is (make sure you don't run into buffer overflows, little endian/big endian issues, etc... just test all edge cases). Then send the file data. Then the ending socket will know which part is the file name, the file length and the file data, and will even be ready for the next file name if you want to send another.

(if file names can be arbitrary characters including control characters, ouch! Maybe send a 64 bit integer length of file name, the file name, a 64 bit integer length of file data, the file data, repeat ad infinitum?)

EDIT: To send a 64 bit integer over a socket, send its constituent bytes in a specific order, and make sure sender and receiver agree on the order. One example of how to do this is How to convert a Java Long to byte[] for Cassandra?

4 Comments

Just make sure to specify, at the byte level, how a 64-bit integer will be sent.
Can you please provide an example. Thanks
@sap I've never done java socket programming before, sorry :(
Java's DataInputStream and DataOutputStream will take care of the details of how to do this, in a well-tested and standardized way (as in VGR's answer). Better not to reinvent the wheel!
1

I tried to wrap a buffer which cause MalfuctionUTF and putting it on try-with resource closes the underlining socket stream and cause connection reset exception
Following code worked for me

Client

DataOutputStream d = new DataOutputStream(out);
        d.writeUTF(filename);
        d.writeLong(length);

Server

DataInputStream d = new DataInputStream(in);
filename = d.readUTF();
fileLength = d.readLong();

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.