用Java Serialization实现任意文件网络传输

来源:互联网 发布:农村人口老龄化数据 编辑:程序博客网 时间:2024/06/03 16:10

摘要:

本文通过Java中提供的Serialization机制,通过网络(Socket)实现任意文件在不同机器之间的传输。本文将包含两个实验的代码:

1.     将文件从一个电脑(客户端),传送到另外一个电脑(服务端)

2.     将文件从一个Android 2.1手机(客户端),通过WiFi传送到电脑(服务端)

 

 

很多朋友发现在两台机器之间,通过TCP socket传送文件的时候,所得到的文件要么比源文件大,要么比源文件小。尤其是在传递多媒体文件的时候,由于文件大小的变化,最终导致多媒体文件无法正常播放。造成这种情况的原因有很多,但100%是程序自身的问题。同样,解决的办法也有很多,本文所介绍的两个小实验,就是试图采用Java中提供的Serialization机制,来解决这样的问题。

 

实验一:

1.     先创建一个Java项目,项目名为ObjectClient,作为客户端应用。在这个项目中创建一个实现了Serializable接口的类FilePojo,代码如下:

package com.pnf.transfer;

 

import java.io.Serializable;

 

// 必须实现Serializable接口否则无法调用ObjectOutputStream

// writeObject方法或者ObjectInputStream中的readObject方法

public class FilePojo implements Serializable

{

         private static final long serialVersionUID = 1L;

        

         private String fileName;            // 文件名称

         private long fileLength;             // 文件长度

         private byte[] fileContent;          // 文件内容

        

         public String getFileName()

         {

                   return fileName;

         }

        

         public void setFileName(String fileName)

         {

                   this.fileName = fileName;

            }

        

            public long getFileLength()

         {

                   return fileLength;

         }

        

         public void setFileLength(long fileLength)

         {

                   this.fileLength = fileLength;

         }

        

         public byte[] getFileContent()

         {

                   return fileContent;

         }

        

         public void setFileContent(byte[] fileContent)

         {

                   this.fileContent = fileContent;

            }

}

这个类将在服务器端也会被用到。

 

2.     编写客户端代码如下

package com.pnf.transfer;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

import java.io.ObjectOutputStream;

import java.net.Socket;

 

public class ObjectClient

{

         public static void main(String[] args)

         {

                   String serverName = "192.168.0.10";                           // 服务器IP

                   int port = 6666;                                                                  // 服务器端口

                   String filePath = "E:\\";                                                      // 要传递文件的路径

                   String fileName = "full.jpg";                                             // 要传递文件的名称

                   try

                   {

                            // 连接服务器

                            System.out.println("Connecting to " + serverName + " on port " + port);

                            Socket client = new Socket(serverName, port);

                            System.out.println("Just connected to " + client.getRemoteSocketAddress());

                           

                            // 创建FilePojo对象

                            FilePojo fpo = new FilePojo();

                           

                            // 设定文件名

                            fpo.setFileName(fileName);

                           

                            // 设定文件大小

                            File f = new File(filePath + fileName);

                            long fileLength = f.length();

                            fpo.setFileLength(fileLength);

                           

                            // 读取文件内容,并将其转换为byte[]

                            FileInputStream fis = new FileInputStream(filePath + fileName);

                            byte[] fileContent = new byte[(int) fileLength];

                            fis.read(fileContent, 0, (int) fileLength);

                            fpo.setFileContent(fileContent);

                           

                            // FilePojo对象fpo写到Socket client指定的输出流

                            long start = System.currentTimeMillis();

                            ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());

                            oos.writeObject(fpo);

                            long end = System.currentTimeMillis();

                           

                            System.out.println("It takes " + (end - start) + "ms");

                            oos.flush();

                            oos.close();

                   }

                   catch(IOException e)

                   {

                            e.printStackTrace();

                   }

         }

}

 

3.     创建另外一个Java项目,项目名为ObjectServer,作为服务端应用。把第1步中的FilePojo.java拷贝到这个项目中来。

 

4.     编写服务端代码如下:

package com.pnf.transfer;

 

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.net.ServerSocket;

import java.net.Socket;

 

public class ObjectServer

{

         public static void main(String[] args) throws ClassNotFoundException

         {

                   ServerSocket serverSocket;

                   FileOutputStream fos;

                  

                   try

                   {

                            serverSocket = new ServerSocket(6666);

                            while(true)

                            {

                                      Socket clientSocket = serverSocket.accept();

                                    

                                     // clientSocket获取ObjectInputStream对象

                                     ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());

                                     // 读取从客户端传递过来的FilePojo对象

                                     FilePojo fpo = (FilePojo) ois.readObject();

                                     System.out.println(fpo.getFileName());

                                     System.out.println(fpo.getFileLength());

                                    

                                     // 初始化FileOutputStream对象fos

                                     fos = new FileOutputStream("D:\\" + fpo.getFileName());

                                     // fpo中的内容写入fpo

                                     fos.write(fpo.getFileContent(), 0, (int)fpo.getFileLength());

                                    

                                     fos.close();

                                     ois.close();

                            }

                   }

                   catch(IOException ioe)

                   {

                            ioe.printStackTrace();

                   }

         }

}

 

5.     测试。

先运行服务端,在运行客户端。

在局域网上,传输的速度大致为:传输162149bytes需要20ms,即8KB/ms8MB/s

 

 

实验二:

服务端的代码和实验一中的一样。

 

1.     创建一个Android项目,项目名为AndroidObjectClient作为客户端。并将实验一中的FilePojo.java拷贝到该项目中。

 

2.     修改main.xml如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    >

 

         <Button android:id="@+id/btn_send"

                   android:layout_width="fill_parent"

                   android:layout_height="wrap_content"

                   android:text="Send a picture to PC!"

         >

         </Button>

</LinearLayout>

 

3.     编写Activity的代码如下:

package com.pnf.transfer;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.ObjectOutputStream;

import java.net.Socket;

import android.app.Activity;

import android.os.Bundle;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.Toast;

 

public class AndroidObjectClientActivity extends Activity

implements

OnClickListener

{

         private Button btn_send;

         private String filePath = "/sdcard/image/";

         private String fileName = "bln.jpg";

    @Override

    public void onCreate(Bundle savedInstanceState)

    {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

       

        btn_send = (Button)this.findViewById(R.id.btn_send);

        btn_send.setOnClickListener(this);

    }

 

         public void onClick(View v)

         {

                   try

                   {

                            // 建立和服务器的连接

                            Socket socket = new Socket("192.168.0.10", 6666);

 

                            // 创建FilePojo对象

                            FilePojo fpo = new FilePojo();

                           

                            // 设定文件名

                            fpo.setFileName(fileName);


                            // 设定文件大小

                            File f = new File(filePath + fileName);

                            long fileLength = f.length();

                            fpo.setFileLength(fileLength);

                           

                            // 读取文件内容,并将其转换为byte[]

                            FileInputStream fis = new FileInputStream(filePath + fileName);

                            byte[] fileContent = new byte[(int) fileLength];

                            fis.read(fileContent, 0, (int) fileLength);

                            fpo.setFileContent(fileContent);

                           

                            // FilePojo对象fpo写到Socket client指定的输出流

                            long start = System.currentTimeMillis();

                            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

                            oos.writeObject(fpo);

                            long end = System.currentTimeMillis();

                            Toast.makeText(this.getApplicationContext(), "It takes " + (end - start) + "ms", Toast.LENGTH_LONG).show();

                            oos.flush();

                            oos.close();

                   }

                   catch(Exception ioe)

                   {

                            ioe.printStackTrace();

                   }

         }

}

 

4.     AndroidManifest.xml中增加permission如下(粗体字部分)

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

      package="com.pnf.transfer"

      android:versionCode="1"

      android:versionName="1.0">

    <application android:icon="@drawable/icon" android:label="@string/app_name">

        <activity android:name=".AndroidObjectClientActivity"

                  android:label="@string/app_name">

            <intent-filter>

                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />

            </intent-filter>

        </activity>

 

    </application>

    <uses-sdk android:minSdkVersion="7" />

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

         <uses-permission android:name="android.permission.INTERNET" />

</manifest>

第一个permission,表示该程序可以读取sd卡上的内容,第二个permission,表示该程序可以联网(因为我们用到了TCP/IP)

 

5.     在手机上安装编译好的AndroidObjectClient.apk

 

6.     运行。

先运行服务端,再在手机上运行客户端。

WLAN(802.11g)网上,传输的速度大致为:传输218089bytes需要200ms,即1.1KB/ms1.1MB/s。如果是802.11n的话,传输速度应该会快很多。

 

当然,也可以将一个文件,通过DDMS放到模拟器中模拟的SD卡里面,然后在模拟器中运行客户端,这点在实验中也经过验证了的。

0 0