2012-04-21 37 views
1

我已經啓動了一個應用程序,它使用序列化對象myfirstpath.UserState保存其狀態。重構後更改序列化Java對象的路徑/類名稱

現在,我想將此對象的路徑更改爲mycleanpath.UserState(同一對象,只更改路徑)。這將適用於第一次安裝應用的新用戶,但對於更新應用的用戶來說,他們將失去他們的狀態。

有沒有辦法將序列化的obect myfirstpath.UserState加載到mycleanpath.UserState中? (當然,在我的源代碼中不保留myfirstpath.UserState)。

回答

3

我寫了一小段代碼來搜索/替換包含序列化數據的文件中的舊路徑/新路徑。我在加載它之前轉換文件,這樣我就可以將序列化的類移動到新路徑,而不必在舊路徑中保留此類的副本。這是你如何使用它:

File baseDirectory = applicationContext.getFilesDir(); 
File file = new File(baseDirectory, "settings.data"); 
if (file.exists()) { 
    //We have to convert it to newsettings.Data 
    byte[] convertedBytes = common.utils.SerializeTools.changePathInSerializedFile(file, "old.path.data", "new.path.data"); 

    //Write converted file 
    File newFile = new File(baseDirectory, "newsettings.data"); 
    FileOutputStream fos = new FileOutputStream(newFile); 
    fos.write(convertedBytes); 
    fos.close(); 

    //Remove old file 
    file.delete(); 
} 

這是SerializeTools.java的代碼。我在這篇偉大的博客文章http://www.javaworld.com/community/node/2915中瞭解到了Java序列化格式。

package common.utils; 

import java.io.ByteArrayOutputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 

public class SerializeTools { 

static public byte[] changePathInSerializedFile(File f, String fromPath, String toPath) throws IOException { 
    byte[] buffer = new byte[(int)f.length()]; 
    FileInputStream in = new FileInputStream(f); 
    in.read(buffer); 
    in.close(); 
    return SerializeTools.changePathInSerializedData(buffer,fromPath,toPath); 
} 

static public byte[] changePathInSerializedData(byte[] buffer, String fromPath, String toPath) throws IOException { 
    byte[] search = fromPath.getBytes("UTF-8"); 
    byte[] replace = toPath.getBytes("UTF-8"); 

    ByteArrayOutputStream f = new ByteArrayOutputStream(); 

    for (int i=0;i<buffer.length;i++) { 
     //Search 2 bytes ahead to let us modify the 2 bytes length of the class name (see Serialize format http://www.javaworld.com/community/node/2915) 
     boolean found=false; 
     int searchMaxIndex=i+search.length+2; 
     if (searchMaxIndex<=buffer.length) { 
      found=true; 
      for (int j=i+2;j<searchMaxIndex;j++) { 
       if (search[j-i-2]!=buffer[j]) { 
        found=false; 
        break; 
       } 
      } 
     } 
     if (found) { 
      int high=((int)(buffer[i])&0xff); 
      int low=((int)(buffer[i+1])&0xff); 
      int classNameLength=(high<<8)+low; 
      classNameLength+=replace.length-search.length; 
      //Write new length 
      f.write((classNameLength>>8)&0xff); 
      f.write((classNameLength)&0xff); 
      //Write replacement path 
      f.write(replace); 
      i=searchMaxIndex-1; 
     } else { 
      f.write(buffer[i]); 
     } 
    } 

    f.flush(); 
    f.close(); 

    return f.toByteArray(); 
} 

} 
1

您必須在您的myfirstpath.UserState類中實施方法readResolve,在Serializable Javadoc處提及。此readResolve必須返回mycleanpath.UserState對象。

+0

看起來不錯,非常感謝,我想我不能擺脫myfirstpath.UserState代碼,但至少用一個方法類替換它。 – jptsetung 2012-04-21 15:52:01

+1

實際上,readResolve是在對象反序列化後調用的,這使得我無法在myfirstpath中刪除我的代碼.UserState – jptsetung 2012-04-22 07:36:07

+0

是的,您現在不會刪除遺留代碼。但是,您可以在用戶升級到新版本後執行此操作。 – 2012-04-22 12:43:40

相關問題