用Java Serialization实现任意文件网络传输
2014-08-02 15:52
309 查看
摘要:
本文通过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/ms或8MB/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/ms或1.1MB/s。如果是802.11n的话,传输速度应该会快很多。
当然,也可以将一个文件,通过DDMS放到模拟器中模拟的SD卡里面,然后在模拟器中运行客户端,这点在实验中也经过验证了的。
本文通过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/ms或8MB/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/ms或1.1MB/s。如果是802.11n的话,传输速度应该会快很多。
当然,也可以将一个文件,通过DDMS放到模拟器中模拟的SD卡里面,然后在模拟器中运行客户端,这点在实验中也经过验证了的。
相关文章推荐
- 用Java Serialization实现任意文件网络传输
- 用Java Serialization实现任意文件网络传输
- 什么是序列化?一句话:就是将java对象固化成文件存起来,这样就java对象就被固话了,可以任意的存储和网络传输了,而java对象是暂时存在内存里的,是没办法传输的,因为是虚拟的,并不是实实在在的文件
- 用java实现基于http协议的网络文件下载
- Java实现任意文件在bmp中的隐藏与导出
- (转)Java 网络文件传输
- Java 网络文件传输
- Java 网络文件传输
- JAVA应用XFire框架来实现WebServie的大文件传输功能之一(下载)
- java p2p多文件传输程序的实现
- 用Java实现基于SOAP的XML文档网络传输及远程过程调用(RPC)
- 用UDP实现在网络上传输文件的问题。
- WinSock实现多线程网络文件传输程序(二)(MFC+WinSock 附源代码)
- 二进制读写文件, 实现任意格式文件的复制以及网络传送
- JAVA应用XFire框架来实现WebServie的大文件传输功能之二(上传)
- 用Java实现基于SOAP的XML文档网络传输及远程过程调用(RPC)(转)
- 使用Java实现网络传输数据的压缩
- Java实现任意文件在bmp中的隐藏与导出
- WinSock实现多线程网络文件传输程序(一)(MFC+WinSock附源代码)
- Java 网络编程 之 传输对象 Serialization 序列化