René Nyffenegger's collection of things on the web
René Nyffenegger on Oracle - Most wanted - Feedback
 

Java: copying files over TCP/IP

I recently experimented with Sockets on Java. I wanted to copy files across TCP/IP and I didn't want to use the serializable interface.... but don't ask why.
The environment consists of three classes: FileReceiver, FileSender and ByteStream. FileReceiver must be started first. When it is started, FileSender can connect onto it and send one or more files to the receiver which will save them. ByteStream is a module to encapsulate all the gory details of persisting data on a stream.

The receiver

The receiver listens on port 4711 (hardcoded). When it is started, no argument needs to be specified.
FileReceiver.java
import java.lang.*;

import java.io.File;
import java.io.InputStream;
import java.io.FileInputStream;
import java.net.Socket;
import java.net.ServerSocket;

public class FileReceiver implements Runnable {

  private static final int port = 4711;

  private Socket socket;

  public static void main(String[] _) {
    try {
      ServerSocket listener = new ServerSocket(port);

      while (true) {
        FileReceiver file_rec = new FileReceiver();
        file_rec.socket = listener.accept();  

        new Thread(file_rec).start();
      }
    }
    catch (java.lang.Exception ex) {
      ex.printStackTrace(System.out);
    }
  }

  public void run() {
    try {
      InputStream in = socket.getInputStream();
  
      int nof_files = ByteStream.toInt(in);
  
      for (int cur_file=0;cur_file < nof_files; cur_file++) {
        String file_name = ByteStream.toString(in);
  
        File file=new File(file_name);
  
        ByteStream.toFile(in, file);
      }
    }
    catch (java.lang.Exception ex) {
      ex.printStackTrace(System.out);
    }
  }
}

The sender

The sender connects to port 4711 on localhost (hardcoded). When it is started, the names of the files need to be specified on the command line.
FileSender.java
import java.lang.*;

import java.io.OutputStream;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import java.net.Socket;


public class FileSender {
  // host and port of receiver
  private static final int    port = 4711;
  private static final String host = "localhost";

  public static void main(String[] args) {
    try {
      Socket       socket = new Socket(host, port);
      OutputStream os     = socket.getOutputStream();
  
      int cnt_files = args.length;
  
      // How many files?
      ByteStream.toStream(os, cnt_files);
  
      for (int cur_file=0; cur_file<cnt_files; cur_file++) {
        ByteStream.toStream(os, args[cur_file]);
        ByteStream.toStream(os, new File(args[cur_file]));
      }
    }
    catch (Exception ex) {
      ex.printStackTrace();
    }
  }
}

ByteStream

ByteStream.java
import java.io.InputStream;
import java.io.OutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileInputStream;

public class ByteStream {
  private static byte[] toByteArray(int in_int) {
    byte a[] = new byte[4];
    for (int i=0; i < 4; i++) {

      int  b_int = (in_int >> (i*8) ) & 255;
      byte b = (byte) ( b_int );
 
      a[i] = b;
     }
    return a;
  }

  private static int toInt(byte[] byte_array_4) {
    int ret = 0;  
    for (int i=0; i<4; i++) {
      int b = (int) byte_array_4[i];
      if (i<3 && b<0) {
        b=256+b;
      }
      ret += b << (i*8);
    }
    return ret;
  }

  public static int toInt(InputStream in) throws java.io.IOException {
    byte[] byte_array_4 = new byte[4];

    byte_array_4[0] = (byte) in.read();
    byte_array_4[1] = (byte) in.read();
    byte_array_4[2] = (byte) in.read();
    byte_array_4[3] = (byte) in.read();

    return toInt(byte_array_4);
  }

  public static String toString(InputStream ins) throws java.io.IOException {
    int len = toInt(ins);
    return toString(ins, len);
  }

  private static String toString(InputStream ins, int len) throws java.io.IOException {
    String ret=new String();
    for (int i=0; i<len;i++) {
      ret+=(char) ins.read();
    }
    return ret;
  }
  
  public static void toStream(OutputStream os, int i) throws java.io.IOException {
    byte [] byte_array_4 = toByteArray(i);
    os.write(byte_array_4);
  }

  public static void toStream(OutputStream os, String s) throws java.io.IOException {
    int len_s = s.length();
    toStream(os, len_s);
    for (int i=0;i<len_s;i++) {
      os.write((byte) s.charAt(i));
    }
    os.flush();
  }

  private static byte[] toByteArray(InputStream ins, int an_int) throws 
    java.io.IOException,  
    Exception{

    byte[] ret = new byte[an_int];

    int offset  = 0;
    int numRead = 0;
    int outstanding = an_int;

    while (
       (offset < an_int)
         &&
      (  (numRead = ins.read(ret, offset, outstanding)) > 0 )
    ) {
      offset     += numRead;
      outstanding = an_int - offset;
    }
    if (offset < ret.length) {
      throw new Exception("Could not completely read from stream, numRead="+numRead+", ret.length="+ret.length); // ???
    }
    return ret;
  }

  private static void toFile(InputStream ins, FileOutputStream fos, int len, int buf_size) throws 
        java.io.FileNotFoundException, 
        java.io.IOException {

    byte[] buffer = new byte[buf_size];

    int       len_read=0;
    int total_len_read=0;

    while ( total_len_read + buf_size <= len) {
      len_read = ins.read(buffer);
      total_len_read += len_read;
      fos.write(buffer, 0, len_read);
    }

    if (total_len_read < len) {
      toFile(ins, fos, len-total_len_read, buf_size/2);
    }
  }

  private static void toFile(InputStream ins, File file, int len) throws 
        java.io.FileNotFoundException, 
        java.io.IOException {

    FileOutputStream fos=new FileOutputStream(file);

    toFile(ins, fos, len, 1024);
  }

  public static void toFile(InputStream ins, File file) throws 
        java.io.FileNotFoundException, 
        java.io.IOException {

    int len = toInt(ins);
    toFile(ins, file, len);
  }

  public static void toStream(OutputStream os, File file) 
      throws java.io.FileNotFoundException,
             java.io.IOException{

    toStream(os, (int) file.length());

    byte b[]=new byte[1024];
    InputStream is = new FileInputStream(file);
    int numRead=0;

    while ( ( numRead=is.read(b)) > 0) {
      os.write(b, 0, numRead);
    }
    os.flush();
  }
}