前一段时间,做了一个对象串行化的实例,今天又写了一个实例,与之前的不同的是,这次串行化不是一个绝对的串行化,而是一个将对象和对象包含的附件(文件)混杂一并写入到一个文件,较之前面的实例来看,这个实例的实用性更强,可以在写入对象和附件后,单独读出对象和单独读出某个附件。就像在蓝杰公司写山寨QQ程序,有些时候需要自定义读写协议。
Head | Object | Attachment1 | Attachment2 | Attachment3 | Attachment4 | ... ... | Attachment n |
long | byte[] | byte[] | byte[] | byte[] | byte[] | byte[] |
注:Head存储了Object串行化所需要的字节数组长度。
Task.java
package cn.hunnu.test1;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.List;
/**
* Task
* @author 肖波
*
*/
public class Task implements Serializable
{
private static final long serialVersionUID = 1L;
private String taskName;
private Timestamp createOn;
private String content;
private Timestamp lastModifiedOn;
private List<Attachment> attachmentList;
public Task()
{
}
public Task(String taskName,Timestamp createOn,String content,Timestamp lastModifiedOn)
{
this.taskName = taskName;
this.createOn = createOn;
this.content = content;
this.lastModifiedOn = lastModifiedOn;
}
public void info()
{
System.out.println("Task Name:"+taskName);
System.out.println("Created On:"+createOn);
System.out.println("Last Modified On:"+lastModifiedOn);
System.out.println("Content:"+content);
System.out.println("Attachments:");
if(attachmentList!=null&&attachmentList.size()>0)
{
int size = attachmentList.size();
for(int i = 0;i<size;i++)
{
System.out.print("att"+i+":");
System.out.println(attachmentList.get(i));
}
}
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public Timestamp getCreateOn() {
return createOn;
}
public void setCreateOn(Timestamp createOn) {
this.createOn = createOn;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Timestamp getLastModifiedOn() {
return lastModifiedOn;
}
public void setLastModifiedOn(Timestamp lastModifiedOn) {
this.lastModifiedOn = lastModifiedOn;
}
public List<Attachment> getAttachmentList() {
return attachmentList;
}
public void setAttachmentList(List<Attachment> attachmentList) {
this.attachmentList = attachmentList;
}
}
Attachment.java
package cn.hunnu.test1;
import java.io.File;
import java.io.Serializable;
public class Attachment implements Serializable
{
private static final long serialVersionUID = 1L;
private File file;
private String fileName;
private String storageID;
private long size;
public Attachment(){}
public Attachment(File file,String fileName,String storageID,long size)
{
this.file = file;
this.fileName = fileName;
this.storageID = storageID;
this.size = size;
}
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getStorageID() {
return storageID;
}
public void setStorageID(String storageID) {
this.storageID = storageID;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append("{File Name:\"");
sb.append(fileName);
sb.append("\",Size:\"");
sb.append(size);
sb.append("\",StorageID:\"");
sb.append(storageID);
sb.append("\"}");
return sb.toString();
}
}
测试类:
package cn.hunnu.test1;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.RandomAccessFile;
import java.util.List;
public class Main
{
public static void main(String args[])
{
Task task = new Task("Serializable Task",new Timestamp(new Date().getTime()),
"Content of Task",new Timestamp(new Date().getTime()));
List<Attachment> attList = new ArrayList<Attachment>();
File f1 = new File("D:\\Documents\\Document for CIM\\Task_Management_Overview_V02.ppt");//1168KB
File f2 = new File("D:\\Documents\\Document for CIM\\2010 Direct Client Satisfaction Surveys.zip");//405KB
File f3 = new File("D:\\Documents\\Document for CIM\\CIM_BottomPanel.pdf");//895KB
Attachment att1 = new Attachment();
att1.setFile(f1);
att1.setFileName("Task_Management_Overview_V02.ppt");
att1.setStorageID("0001");
att1.setSize(f1.length());
Attachment att2 = new Attachment();
att2.setFile(f2);
att2.setFileName("2010 Direct Client Satisfaction Surveys.zip");
att2.setStorageID("0002");
att2.setSize(f2.length());
Attachment att3 = new Attachment();
att3.setFile(f3);
att3.setFileName("CIM_BottomPanel.pdf");
att3.setStorageID("0003");
att3.setSize(f3.length());
attList.add(att1);
attList.add(att2);
attList.add(att3);
task.setAttachmentList(attList);
//write to file
write(task);
//read from file
Task retrievedTask1 = readTaskObject();
Task retrievedTask2 = readTaskAll();
retrievedTask1.info();
retrievedTask2.info();
//get assigned file
getFile("Task_Management_Overview_V02.ppt","0001");
getFile("2010 Direct Client Satisfaction Surveys.zip","0002");
getFile("CIM_BottomPanel.pdf","0003");
}
public static void write(Task task)
{
try{
//create a memory output stream.
ByteArrayOutputStream bops = new ByteArrayOutputStream();
ObjectOutputStream fout = new ObjectOutputStream(bops);
fout.writeObject(task);
fout.flush();
fout.close();//close ObjectOutputStream and close ByteArrayOutputStream
//get the length of serialized Object
byte[] objectByteArray = bops.toByteArray();
long lengthOfObject = objectByteArray.length;
//write to file
File targetFile = new File("D:/object1.txt");
FileOutputStream fis = new FileOutputStream(targetFile);
BufferedOutputStream bout = new BufferedOutputStream(fis);
//1,write Object length
DataOutputStream dos = new DataOutputStream(fis);
dos.writeLong(lengthOfObject);//write the Head.
dos.flush();
//2,write Object
bout.write(objectByteArray);//write the object.
//3,write attachment files
List<Attachment> attList = task.getAttachmentList();
if(attList!=null&&attList.size()>0)
{
BufferedInputStream bis;
for(Attachment att : attList)
{
File file = att.getFile();
if(file!=null)
{
bis = new BufferedInputStream(new FileInputStream(file));
byte[] per = new byte[1024];//1KB
long count = att.getSize()/per.length;
long residueBytes = att.getSize()%per.length;
for(int j = 0;j<count;j++)
{
bis.read(per);
bout.write(per);
}
if(residueBytes>0){
byte[] left = new byte[(int)residueBytes];
bis.read(left);
bout.write(left);
}
bis.close();
}
else
{
bout.write(new byte[0]);
}
}
}
bout.flush();
bout.close();
}catch(Exception e){
e.printStackTrace();
}
}
public static Task readTaskObject()
{
Task task = null;
try
{
File objectFile = new File("D:/object1.txt");
FileInputStream fis = new FileInputStream(objectFile);
DataInputStream dis = new DataInputStream(fis);
//read head:length of Object
long objectLength = dis.readLong();
//read object
byte[] objectByteArray = new byte[(int) objectLength];
dis.read(objectByteArray);
ByteArrayInputStream bis = new ByteArrayInputStream(objectByteArray);
ObjectInputStream ois = new ObjectInputStream(bis);
task = (Task)ois.readObject();
ois.close();
dis.close();
}
catch(Exception e)
{
e.printStackTrace();
}
return task;
}
public static Task readTaskAll()
{
Task task = null;
try
{
File objectFile = new File("D:/object1.txt");
FileInputStream fis = new FileInputStream(objectFile);
DataInputStream dis = new DataInputStream(fis);
//read head:length of Object
long objectLength = dis.readLong();
//read object
byte[] objectByteArray = new byte[(int) objectLength];
dis.read(objectByteArray);
ByteArrayInputStream bis = new ByteArrayInputStream(objectByteArray);
ObjectInputStream ois = new ObjectInputStream(bis);
task = (Task)ois.readObject();
ois.close();
//read attachment files
List<Attachment> attachList = task.getAttachmentList();
if(attachList!=null&&attachList.size()>0)
{
String tempDir = "D:/tmp1/";
// FileOutputStream fos;
BufferedOutputStream bout;
for(Attachment att : attachList)
{
String fileName = att.getFileName();
File tempFile = new File(tempDir+fileName);
if(!tempFile.exists()){
tempFile.createNewFile();
}
long size = att.getSize();
// fos = new FileOutputStream(tempFile);
bout = new BufferedOutputStream(new FileOutputStream(tempFile));
//for cycle
byte[] per = new byte[1024];//1KB
long count = size/per.length;
long residueBytes = size%per.length;
for(int j = 0;j<count;j++)
{
dis.read(per);
bout.write(per);
}
if(residueBytes>0){
byte[] left = new byte[(int)residueBytes];
//in.read(left);
//fos.write(left);
dis.read(left);
bout.write(left);
}
//for cycle
bout.flush();
bout.close();
}
}
dis.close();
}
catch(Exception e)
{
e.printStackTrace();
}
return task;
}
/**
* the file which get from stream will be saved at the path "D:\\downloadFile"
* @param fileName
* @param storageID
*/
public static void getFile(String fileName ,String storageID)
{
try
{
File objectFile = new File("D:/object1.txt");
FileInputStream fis = new FileInputStream(objectFile);
DataInputStream dis = new DataInputStream(fis);
//read head:length of Object
long objectLength = dis.readLong();
//read object
byte[] objectByteArray = new byte[(int) objectLength];
dis.read(objectByteArray);
ByteArrayInputStream bis = new ByteArrayInputStream(objectByteArray);
ObjectInputStream ois = new ObjectInputStream(bis);
Task task = (Task)ois.readObject();
ois.close();
dis.close();
//read attachment files
int off = (int) (objectLength+8);
List<Attachment> attachList = task.getAttachmentList();
if(attachList!=null&&attachList.size()>0)
{
String downloadDir = "D:/downloadFile/";
BufferedOutputStream bout;
RandomAccessFile raf = new RandomAccessFile(objectFile,"r");
for(Attachment att : attachList)
{
if(!storageID.equals(att.getStorageID()))
{
// move offset
off+=att.getSize();
}
else
{
raf.seek(off);
//String file_name = att.getFileName();
File tempFile = new File(downloadDir+fileName);
if(!tempFile.exists()){
tempFile.createNewFile();
}
long size = att.getSize();
bout = new BufferedOutputStream(new FileOutputStream(tempFile));
//for cycle
int per_r_length = 1024;//1KB per read
byte[] per = new byte[per_r_length];//1KB
int count = (int) (size/per_r_length);
int residueBytes = (int) (size%per_r_length);
for(int i = 0;i<count;i++)
{
raf.read(per);
bout.write(per);
per = new byte[per_r_length];
}
if(residueBytes>0){
byte[] left = new byte[(int)residueBytes];
raf.read(left);
bout.write(left);
}
//for cycle
bout.flush();
bout.close();
break;
}
}
}
dis.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
注意:Task类中的serialVersionUID 属性非常重要,用于标识串行化对象的版本,可以做向前兼容和向后兼容。