Pages

Saturday, 31 May 2014

Send Multiple Files over a single Socket Connnection

This post will explain the a sample implementation to send a folder over a Socket and read the same on the Client. The first challenge is parse all the files on the Server side of the program and write the file to the output stream.
This poses a challenge as the client needs to read the bytes received and also be able to identify each file and folder so that the same can be written back. To overcome the challenge, I decided to explore the use of ZipOutputStream, where I could add each file into this output stream which writes directory to the Socket instead of the file. On the client side, I wrote the program to read the stream and replicate the folders and files.

Refer this blog for a detailed example with source code for an implementation using ZipOutputStream to write files into the network and read the the file on the client using ZipInputStream.

Code on the Server Side:

package com.gt.stick2code.filestream;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class SendFileSocketServer extends Thread {
 private static ServerSocket serverSocket;
 private Socket socket;
 private static int MAX_READ_SIZE = 1024;

 public SendFileSocketServer(Socket socket) {
  this.socket = socket;
 }

 public static void main(String[] args) throws FileNotFoundException,
   IOException {
  serverSocket = new ServerSocket(50000);
  while (true) {
   SendFileSocketServer socServer = new SendFileSocketServer(
     serverSocket.accept());
   socServer.start();
  }

 }

 public void run() {
  try {
   System.out.println("Connected");

   BufferedInputStream bis = new BufferedInputStream(
     socket.getInputStream());
   byte[] bytesToRead = new byte[MAX_READ_SIZE];
   String copyFolder = "";
   System.out.println("Reading");
   int readLength = 0;
   while (0 != (readLength = bis.read(bytesToRead))) {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    bos.write(bytesToRead, 0, readLength);
    System.out.println("Reading::"+new String(bos.toByteArray()));
    copyFolder += new String(bos.toByteArray());
    if(readLength < MAX_READ_SIZE){
     break;
    }
   }

   File readFile = new File(copyFolder);
   if (readFile.exists()) {
    System.out.println("Reading Folder::" + copyFolder);
    ZipOutputStream zipOpStream = new ZipOutputStream(
      socket.getOutputStream());
    sendFileOutput(zipOpStream, readFile);
    zipOpStream.flush();
    System.out.println("zipOpStream Flush");

   } else {
    System.out.println("Folder to read does not exist::["+readFile.getAbsolutePath()+"]");
   }
   socket.close();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

 public void sendFileOutput(ZipOutputStream zipOpStream, File outFile)
   throws Exception {
  String relativePath = outFile.getAbsoluteFile().getParentFile()
    .getAbsolutePath();
  System.out.println("relativePath[" + relativePath + "]");
  outFile = outFile.getAbsoluteFile();
  if (outFile.isDirectory()) {
   sendFolder(zipOpStream, outFile, relativePath);

  } else {
   sendFolder(zipOpStream, outFile, relativePath);
  }
 }

 public void sendFolder(ZipOutputStream zipOpStream, File folder,
   String relativePath) throws Exception {
  File[] filesList = folder.listFiles();
  for (File file : filesList) {
   if (file.isDirectory()) {
    sendFolder(zipOpStream, file, relativePath);
   } else {
    sendFile(zipOpStream, file, relativePath);
   }
  }
 }

 public void sendFile(ZipOutputStream zipOpStream, File file,
   String relativePath) throws Exception {
  String absolutePath = file.getAbsolutePath();
  String zipEntryFileName = absolutePath;
  int index = absolutePath.indexOf(relativePath);
  if(absolutePath.startsWith(relativePath)){
   zipEntryFileName = absolutePath.substring(relativePath.length());
   if(zipEntryFileName.startsWith(File.separator)){
    zipEntryFileName = zipEntryFileName.substring(1);
   }
   System.out.println("zipEntryFileName:::"+relativePath.length()+"::"+zipEntryFileName);
  }else{
   throw new Exception("Invalid Absolute Path");
  }
  
  BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
    file));
  byte[] fileByte = new byte[MAX_READ_SIZE];
  int readBytes = 0;
  CRC32 crc = new CRC32();
  while (0 != (readBytes = bis.read(fileByte))) {
   if(-1 == readBytes){
    break;
   }
   //System.out.println("length::"+readBytes);
   crc.update(fileByte, 0, readBytes);
  }
  bis.close();
  ZipEntry zipEntry = new ZipEntry(zipEntryFileName);
  zipEntry.setMethod(ZipEntry.STORED);
  zipEntry.setCompressedSize(file.length());
  zipEntry.setSize(file.length());
  zipEntry.setCrc(crc.getValue());
  zipOpStream.putNextEntry(zipEntry);
  bis = new BufferedInputStream(new FileInputStream(file));
  //System.out.println("zipEntryFileName::"+zipEntryFileName);
  while (0 != (readBytes = bis.read(fileByte))) {
   if(-1 == readBytes){
    break;
   }
   
   zipOpStream.write(fileByte, 0, readBytes);
  }
  bis.close();
  
 }

}


Code on Client Side to Read the File:


package com.gt.stick2code.filestream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class SendFileSocketClient {

 public static void main(String[] args) throws FileNotFoundException,
   IOException {
  
  String outDir = "D:\\temp\\output";
  
  String readDir = ".\\amazon";
  System.out.print("Connectiong");
  Socket socket = new Socket("127.0.0.1", 50000);
  BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
  System.out.print("Read::"+readDir);
  bos.write(readDir.getBytes());
  bos.flush();
  BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
  readZip(bis,outDir);
  //socket.close();
  
 }
 
 public static void readZip(InputStream socketIs,String outPutDirectory) throws IOException{
  ZipInputStream zips = new ZipInputStream(socketIs);
  ZipEntry zipEntry = null;
  
  
  while(null != (zipEntry = zips.getNextEntry())){
   String fileName = zipEntry.getName();
   File outFile = new File(outPutDirectory + "/" + fileName);
   System.out.println("----["+outFile.getName()+"], filesize["+zipEntry.getCompressedSize()+"]");
   
   
   if(zipEntry.isDirectory()){
    File zipEntryFolder = new File(zipEntry.getName());
    if(zipEntryFolder.exists() == false){
     outFile.mkdirs();
    }
    
    continue;
   }else{
    File parentFolder = outFile.getParentFile();
    if(parentFolder.exists() == false){
     parentFolder.mkdirs();
    }
   }
   
   System.out.println("ZipEntry::"+zipEntry.getCompressedSize());
   
   
   
   FileOutputStream fos = new FileOutputStream(outFile);
   int fileLength = (int)zipEntry.getSize();
   
   byte[] fileByte = new byte[fileLength];
   zips.read(fileByte);
   fos.write(fileByte);
   fos.close();
  }
 }

}



No comments:

Post a Comment