最近碰到个需求,为了提高传输速度,打算压缩、传输、解压同时进行,即服务端压缩、传输并发执行,客户端接收、解压并发进行;折腾来折腾去,倒也有些进展。下面先贴出代码,结合代码讲解。
服务端代码:
public class Hzipserver extends Thread { //无论文件,还是文件夹都是一个ZipEntry。 /** * 这里默认所有文件都可以读写,但在实际应用中, * 为了程序的健壮性,必须判断文件是否可读、可写, * 是否是隐藏文件等,在安卓里这种情形很常见。 * 例如,不可读的文件,自然也就没法传输了。 * @param file 要传送的文件夹。 * @param zos 包装后的socket的outputstream * @param b 缓存所用。一个容器。 */ private void zipEntry(File file,ZipOutputStream zos,byte[] b) { if(file.isDirectory())//如果文件是目录,就没什么需要传输的了, //只要在zos里放进一个ZipEntry,然后递归它里面的文件 { //ZipEntry有个方法isDirectory(),可判断该ZipEntry表示的 //而是不是目录(文件夹),依据就是该ZipEntry的name是不是以“/”结尾的。 ZipEntry ze=new ZipEntry(file.getAbsolutePath()+"/"); try { zos.putNextEntry(ze); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } File[] files=file.listFiles(); for(File f:files) { zipEntry(f, zos,b); } } else { ZipEntry ze=new ZipEntry(file.getAbsolutePath()); try { zos.putNextEntry(ze); FileInputStream ins=new FileInputStream(file); int length=-1; while( (length=ins.read(b))>-1 ) { zos.write(b, 0, length); zos.flush(); } zos.closeEntry(); zos.flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } @Override public void run() { // TODO Auto-generated method stub // TODO Auto-generated method stub ServerSocket ss = null; java.net.Socket s=null; try { ss = new ServerSocket(10100); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } while(true) { try { s=ss.accept(); //要发送出去的文件夹。请注意在不同操作系统上,表示方法可能不一样。 File file =new File("D:/zipfolder"); OutputStream os=s.getOutputStream(); ZipOutputStream gout=new ZipOutputStream(os); byte[] b=new byte[1024]; zipEntry(file, gout,b); s.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } 客户端代码: public class Hzipclient extends Thread { @Override public void run() { // TODO Auto-generated method stub try { Socket s=new Socket("192.168.0.1",10100); InputStream ins=s.getInputStream(); ZipInputStream zis=new ZipInputStream(ins); String rootDir=null; //在此次连接中,是否是第一次读到ZipEntry。读到的第一个Entry,就是正在被传输的文件夹。 boolean isFirst=true; String savePath="D:"+File.separator+"gitspace"+File.separator; //以上为保存接收到的文件夹的位置。 //如,服务端传输的文件夹是D:\zipfolder,则该文件夹在客户端将保存在D:\gitspace\。 //为了良好的移植性,这里用File.separator, //因为分隔符在不同的操作系统上,可能不一样。 ZipEntry ze=null; ZipOutputStream zos=null; FileOutputStream fos=null; OutputStream os=null; byte[] b=new byte[1024]; int length=-1; while( (ze=zis.getNextEntry())!=null ) { String name=ze.getName(); File file=null; if(ze.isDirectory()) { if(isFirst) { isFirst=false; //这里可能移植性不好,我还没研究透,暂用此法。 String[] temp=name.split("\\\\"); //文件夹的名字。参看服务端代码可知,这个名字是“/”结尾的。 String selfName=temp[temp.length-1]; //去掉“/”,这里才是真正的文件夹的名字。 //后面接收到的文件将要以rootDir为参照物,确定保存位置。 rootDir=selfName.substring(0, selfName.length()-1); //到了这里,这个文件夹的路径其实就是D:\gitspace\zipfolder了。 file=new File(savePath+selfName); } int index=name.indexOf(rootDir); //如,该文件在服务端的位置是D:\zipfolder\a.txt,则tempDir=zipfolder\a.txt String tempDir=name.substring(index,name.length()); //两者拼合,该文件在客户端的保存路径也就是D:\gitspace\zipfolder\a.txt了。 //相对于ziplolder,该文件的位置未发生变化。 file=new File(savePath+tempDir); if(!file.exists()) { file.mkdirs(); } } else { int index=name.indexOf(rootDir); String tempFileDir=name.substring(index,name.length()); file=new File(savePath+tempFileDir); fos=new FileOutputStream(file); while( (length=zis.read(b))>-1 ) { fos.write(b, 0, length); } //这句必须有,不然文件多了,打开的文件过多,将会发生异常 fos.close(); } } s.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
其实这么做到底是不是算压缩、传输、解压同时进行,我还没研究透。尤其发现,我发送出来的字节数其实跟原文件的字节数是一样的,并没有想象中可能会体积变小,而客户端接收到的字节数也是原文件的体积大小。有明白的还请赐教。
