<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 495,comments - 227,trackbacks - 0
      序言:
      
      由于前些時(shí)間,一些matrixer常問(wèn)關(guān)于j2me中使用Pak文件的問(wèn)題。本人雖學(xué)藝不深,但滿懷熱心的做了一番探索,現(xiàn)將制作Pak文件的看法和方法公布出來(lái),大家多多提意見(jiàn)。
      
      一、什么是Pak文件:
      
      Pak文件就是將多個(gè)文件打包為一個(gè)單獨(dú)文件,在這個(gè)文件中保存著多個(gè)文件的數(shù)據(jù),當(dāng)然還有一些描述文件結(jié)構(gòu)的數(shù)據(jù)。所以將“Pak”作為文件的后綴是一種常規(guī)的用法,大家可以自定義其它的文件后綴。
      
      二、為什么使用Pak文件:
      
      由于MIDP對(duì)發(fā)布安裝的j2me程序大小進(jìn)行了限制,所以縮小發(fā)布程序就意味著能夠提供更多的程序或者內(nèi)容(如圖片、音樂(lè))給用戶。而通過(guò)研究發(fā)現(xiàn)zip/jar算法對(duì)大文件的壓縮率高于對(duì)等量的多個(gè)小文件的壓縮率。
      
      當(dāng)然還有其它方法,這里簡(jiǎn)單做一下討論比如使用混淆器ProGuard的“-overloadaggressively”選項(xiàng)使jar文件縮小,但也會(huì)導(dǎo)致一些錯(cuò)誤,因?yàn)檫@種方法生成jar中的class符合java byte code標(biāo)準(zhǔn),但是與java語(yǔ)法相悖,嚴(yán)重的可能造成一些jre對(duì)Object的序列化錯(cuò)誤。
      
      所以使用Pak方法將程序中要用到的資源(圖片、音樂(lè)、文本)組合為單一文件是一個(gè)安全有效的方法。而且對(duì)于一些商用程序,完全可以在pak文件中對(duì)文件數(shù)據(jù)進(jìn)行加密,很好的保護(hù)了作者和公司的權(quán)益。本人的sample中使用了簡(jiǎn)單的“加減法”加密,對(duì)于手機(jī)這類設(shè)備來(lái)講是一個(gè)效率較高的選擇。
      
      三、Pak文件的結(jié)構(gòu):
      
      大家可以自己設(shè)計(jì)Pak文件結(jié)構(gòu),本人這里只是拋磚引玉的作個(gè)sample。下面就是本人設(shè)計(jì)的Pak文件結(jié)構(gòu):
      
      PAK File Header:Pak文件的頭部
      
      * 簽名:6字節(jié)char數(shù)組 * 版本號(hào):32位float * 文件table數(shù)量:32位整數(shù) * 密碼行為:8位字節(jié) * 密碼:8位字節(jié) * 文件唯一ID:10字節(jié)char數(shù)組 * 保留位:32位整數(shù)(4字節(jié))
      
      File Table:Pak文件中包含文件的列表,在一個(gè)Pak文件中一個(gè)被包含的文件對(duì)應(yīng)一個(gè)File Table。
      
      * 文件名:30字節(jié)char數(shù)組 * 文件大小:32位整型 * 文件在pak文件中的位移:32位整數(shù)
      
      Concatenated File Data:按File Table的順序連接在一起的文件數(shù)據(jù)。
      * 文件數(shù)據(jù)
      
      四、程序框架:
      
      說(shuō)明:由于Pak文件的制作和使用分別要使用兩個(gè)java應(yīng)用領(lǐng)域:j2se和j2me,所以本人將PakUtil類制作了2個(gè)版本(j2se和j2me)。
      
      程序框架如下:
      1。PakHeader類,定義了Pak文件頭。
      2。PakFileTable類,定義Pak文件table。
      3。PakUtil類(j2se版),具備兩個(gè)功能:將多個(gè)png圖片合成一個(gè)Pak文件,并使用簡(jiǎn)單的加減加密法對(duì)其進(jìn)行加密;從Pak文件中取出png圖片,構(gòu)造byte數(shù)組(可以用來(lái)構(gòu)造Image對(duì)象)或者寫(xiě)為文件。
      PakUtil類(j2me版),具備的功能:從Pak文件中取出png圖片,構(gòu)造byte數(shù)組(可以用來(lái)構(gòu)造Image對(duì)象)。
      
      五、PakHeader和PakFileTable類:
      
      PakHeader.java:
      package cn.org.matrix.gmatrix.gameLab.util.pak;/** * Pak文件頭: * 結(jié)構(gòu): *
      簽名:6字節(jié)char數(shù)組 *  版本號(hào):32位float *
      文件table數(shù)量:32位整數(shù) *
      密碼行為:8位字節(jié) *  密碼:8位字節(jié) *
      文件唯一ID:10字節(jié)char數(shù)組 *
      保留位:32位整數(shù)(4字節(jié)) * @author cleverpig * */class PakHeader {
      //定義文件唯一ID長(zhǎng)度
      public static final int UNIQUEID_LENGTH=10;
      //定義文件簽名長(zhǎng)度
      public static final int SIGNATURE_LENGTH=6;
      //定義加法運(yùn)算
      public static final int ADDITION_CIPHERACTION=0;
      //定義減法運(yùn)算
      public static final int SUBTRACT_CIHOERACTION=1;
      //文件簽名
      private char[] signature=new char[SIGNATURE_LENGTH];
      //版本號(hào)
      private float version=0f;
      //文件table數(shù)量
      private long numFileTableEntries=0;
      //密碼使用方法:在原數(shù)據(jù)上進(jìn)行加法還是減法
      private byte cipherAction=ADDITION_CIPHERACTION;
      //密碼值
      private byte cipherValue=0x00;
      //唯一ID
      private char[] uniqueID=new char[UNIQUEID_LENGTH];
      //保留的4字節(jié)
      private long reserved=0;
      public PakHeader(){
      }
      /**
      * 構(gòu)造方法
      * @param signature 簽名
      * @param version 版本
      * @param numFileTableEntries 文件table數(shù)量
      * @param cipherAction 密碼使用方法
      * @param cipherValue 密碼值
      * @param uniqueID 唯一ID
      * @param reserved 保留的2字節(jié)
      */
      public PakHeader(char[] signature,float version,
      long numFileTableEntries,byte cipherAction,
      byte cipherValue,char[] uniqueID,long reserved){
      for(int i=0;i<SIGNATURE_LENGTH;this.signature[i]=signature[i],i++)
      ;
      this.version=version;
      this.cipherAction=cipherAction;
      this.numFileTableEntries=numFileTableEntries;
      this.cipherValue=cipherValue;
      for(int i=0;i<UNIQUEID_LENGTH;this.uniqueID[i]=uniqueID[i],i++);
      this.reserved=reserved;
      }        
      public byte getCipherValue() {
      return cipherValue;    
      }
      public void setCipherValue(byte cipherValue) {
      this.cipherValue = cipherValue;
      }
      public long getNumFileTableEntries() {
      return numFileTableEntries;
      }
      public void setNumFileTableEntries(long numFileTableEntries) {
      this.numFileTableEntries = numFileTableEntries;
      }
      public long getReserved() {
      return reserved;
      }
      public void setReserved(long reserved) {
      this.reserved = reserved;
      }
      public char[] getUniqueID() {
      return uniqueID;
      }
      public void setUniqueID(char[] uniqueID) {
      for(int i=0;i<UNIQUEID_LENGTH;this.uniqueID[i]=uniqueID[i],i++)
      ;    
      }    
      public float getVersion() {
      return version;
      }    
      public void setVersion(float version) {
      this.version = version;
      }
      public byte getCipherAction() {
      return cipherAction;
      }
      public void setCipherAction(byte cipherAction) {
      this.cipherAction = cipherAction;
      }
      public char[] getSignature() {
      return signature;
      }
      public void setSignature(char[] signature) {
      for(int i=0;i<SIGNATURE_LENGTH;this.signature[i] = signature[i],i++)
      ;    
      }
      /**
      * 返回PakHeader的大小
      * @return 返回PakHeader的大小
      */    
      public static int size(){
      return SIGNATURE_LENGTH+4+4+1+1+UNIQUEID_LENGTH+4;
      }
      public String toString(){
      String result="";
      result+="\t簽名:"+new String(this.signature).trim()
      +"\t版本號(hào):"+this.version
      +"\t文件table數(shù)量:"+this.numFileTableEntries
      +"\t密碼行為:" +this.cipherAction
      +"\t密碼:"+this.cipherValue            
      +"\t文件唯一ID:"+new String(this.uniqueID).trim()            +"\t保留位:"+this.reserved;        
      return result;    
      }}
      
      PakFileTable.java
      package cn.org.matrix.gmatrix.gameLab.util.pak;/** * Pak文件table類 * 文件table結(jié)構(gòu): *
      文件名:30字節(jié)char數(shù)組 *
      文件大?。?2位整型 *
      文件在pak文件中的位移:32位整數(shù) * @author cleverpig * */class PakFileTable {
      public static final int FILENAME_LENGTH=30;
      //文件名
      private char[] fileName=new char[FILENAME_LENGTH];
      //文件大小
      private long fileSize=0L;
      //文件在pak文件中的位移
      private long offSet=0L;
      public PakFileTable(){
      }
      /**
      * 構(gòu)造方法
      * @param fileName 文件名
      * @param fileSize 文件大小
      * @param offSet 文件在Pak文件中的位移
      */
      public PakFileTable(char[] fileName,
      long fileSize,long offSet){
      for(int i=0;i<FILENAME_LENGTH;this.fileName[i]=fileName[i],i++)
      ;        this.fileSize=fileSize;
      this.offSet=offSet;
      }
      public char[] getFileName() {
      return fileName;
      }
      public void setFileName(char[] fileName) {
      for(int i=0;i<fileName.length;this.fileName[i]=fileName[i],i++)
      ;    
      }
      public long getFileSize() {
      return fileSize;
      }
      public void setFileSize(long fileSize) {
      this.fileSize = fileSize;
      }
      public long getOffSet() {
      return offSet;
      }
      public void setOffSet(long offSet) {
      this.offSet = offSet;
      }
      /**
      * 返回文件Table的大小
      * @return 返回文件Table的大小
      */    
      public static int size(){
      return FILENAME_LENGTH+4+4;
      }
      public String toString(){
      return "\t文件名:"+new String(this.fileName).trim()
      +"\t文件大小:"+this.fileSize
      +"\t文件位移:"+this.offSet;
      }}
      
      六、PakUtil類(j2se版):
      
      PakUtil.java
      package cn.org.matrix.gmatrix.gameLab.util.pak;import java.io.*;
      import java.util.Vector;
      /** * Pak工具類 * 功能:
      *1.將多個(gè)png圖片合成一個(gè)Pak文件,并使用簡(jiǎn)單的加減加密法對(duì)其進(jìn)行加密;
      * 2.從Pak文件中取出png圖片,構(gòu)造byte數(shù)組(可以用來(lái)構(gòu)造Image對(duì)象)或者寫(xiě)為文件 * @author cleverpig * */public class PakUtil {
      public PakUtil(){
      }
      /**
      * 返回文件長(zhǎng)度
      * @param filePath 文件路徑
      * @return 文件長(zhǎng)度
      */
      private long getFileSize(String filePath){
      File file=new File(filePath);
      return file.length();
      }
      /**
      * 返回文件名
      * @param filePath 文件路徑
      * @return 文件名
      */
      
      private String getFileName(String filePath){
      File file=new File(filePath);
      return file.getName();
      }
      /**
      * 計(jì)算文件位移的起始點(diǎn)
      * @return 文件位移的起始點(diǎn)
      */
      private long workOutOffsetStart(PakHeader header){
      //計(jì)算出文件頭+文件table的長(zhǎng)度
      return PakHeader.size()+header.getNumFileTableEntries()*PakFileTable.size();
      }
      /**
      * 計(jì)算文件位移
      * @param fileIndex 文件序號(hào)
      * @param lastFileOffset 上一個(gè)文件位移
      * @return 文件在pak文件中的位移
      */
      private long workOutNextOffset(long sourceFileSize,long lastFileOffset){
      return lastFileOffset+sourceFileSize;    
      }
      /**
      * 生成文件table
      * @param sourceFileName 源文件名
      * @param sourceFileSize 源文件長(zhǎng)度
      * @param currentFileOffset 當(dāng)前文件位移
      * @return 生成的PakFileTable對(duì)象
      */    
      private PakFileTable generateFileTable(String sourceFileName,
      long sourceFileSize,long currentFileOffset){
      PakFileTable ft=new PakFileTable();
      ft.setFileName(sourceFileName.toCharArray());
      ft.setFileSize(sourceFileSize);
      ft.setOffSet(currentFileOffset);
      return ft;
      }
      /**
      * 將char字符數(shù)組寫(xiě)入到DataOutputStream中
      * @param toWriteCharArray 被寫(xiě)入的char數(shù)組
      * @param dos DataOutputStream
      * @throws Exception
      */    
      private void writeCharArray(char[] toWriteCharArray,DataOutputStream dos) throws Exception{
      for(int i=0;i<toWriteCharArray.length;dos.writeChar(toWriteCharArray[i]),i++);
      }        
      /**
      * 使用文件頭中的密碼對(duì)數(shù)據(jù)進(jìn)行加密
      * @param buff 被加密的數(shù)據(jù)
      * @param buffLength 數(shù)據(jù)的長(zhǎng)度
      * @param header 文件頭
      */
      private void encryptBuff(byte[] buff,int buffLength,PakHeader header){
      for(int i=0;i<buffLength;i++){
      switch(header.getCipherAction()){
      case PakHeader.ADDITION_CIPHERACTION:
      buff[i]+=header.getCipherValue();
      break;
      case PakHeader.SUBTRACT_CIHOERACTION:
      buff[i]-=header.getCipherValue();
      break;
      }
      }
      }
      /**
      * 使用文件頭中的密碼對(duì)數(shù)據(jù)進(jìn)行解密
      * @param buff 被解密的數(shù)據(jù)
      * @param buffLength 數(shù)據(jù)的長(zhǎng)度
      * @param header 文件頭
      */
      private void decryptBuff(byte[] buff,int buffLength,PakHeader header){
      for(int i=0;i<buffLength;i++){
      switch(header.getCipherAction()){
      case PakHeader.ADDITION_CIPHERACTION:
      buff[i]-=header.getCipherValue();
      break;
      case PakHeader.SUBTRACT_CIHOERACTION:
      buff[i]+=header.getCipherValue();
      break;
      }
      }
      }
      /**
      * 制作Pak文件
      * @param sourceFilePath 源文件路徑數(shù)組
      * @param destinateFilePath 目的文件路徑(Pak文件)
      * @param cipherAction 密碼行為
      * @param cipherValue 密碼
      * @throws Exception
      */
      public void makePakFile(String[] sourceFilePath,
      String destinateFilePath,PakHeader header) throws Exception{
      PakFileTable[] fileTable=new PakFileTable[sourceFilePath.length];
      //計(jì)算文件位移起始點(diǎn)
      long fileOffset=workOutOffsetStart(header);
      //逐個(gè)建立文件table
      for(int i=0;i<sourceFilePath.length;i++){
      String sourceFileName=getFileName(sourceFilePath[i]);
      long sourceFileSize=getFileSize(sourceFilePath[i]);
      PakFileTable ft=generateFileTable(sourceFileName,sourceFileSize,fileOffset);
      //計(jì)算下一個(gè)文件位移
      fileOffset=workOutNextOffset(sourceFileSize,fileOffset);
      fileTable[i]=ft;
      }
      //寫(xiě)入文件頭
      File wFile=new File(destinateFilePath);
      FileOutputStream fos=new FileOutputStream(wFile);
      DataOutputStream dos=new DataOutputStream(fos);
      writeCharArray(header.getSignature(),dos);
      dos.writeFloat(header.getVersion());
      dos.writeLong(header.getNumFileTableEntries());
      dos.writeByte(header.getCipherAction());
      dos.writeByte(header.getCipherValue());
      writeCharArray(header.getUniqueID(),dos);
      dos.writeLong(header.getReserved());
      //寫(xiě)入文件table
      for(int i=0;i<fileTable.length;i++){
      writeCharArray(fileTable[i].getFileName(),dos);
      dos.writeLong(fileTable[i].getFileSize());
      dos.writeLong(fileTable[i].getOffSet());
      }
      //寫(xiě)入文件數(shù)據(jù)
      for(int i=0;i<fileTable.length;i++){
      File ftFile=new File(sourceFilePath[i]);
      FileInputStream ftFis=new FileInputStream(ftFile);
      DataInputStream ftDis=new DataInputStream(ftFis);
      byte[] buff=new byte[256];
      int readLength=0;
      while((readLength=ftDis.read(buff))!=-1){
      encryptBuff(buff,readLength,header);
      dos.write(buff,0,readLength);
      }
      ftDis.close();
      ftFis.close();
      }
      dos.close();
      }
      /**
      * 從DataInputStream讀取char數(shù)組     * @param dis DataInputStream
      * @param readLength 讀取長(zhǎng)度
      * @return char數(shù)組
      * @throws Exception
      */
      private char[] readCharArray(DataInputStream dis,int readLength) throws Exception{
      char[] readCharArray=new char[readLength];
      for(int i=0;i<readLength;i++){
      readCharArray[i]=dis.readChar();
      }
      return readCharArray;
      }
      /**
      * 從PAK文件中讀取文件頭
      * @param dis DataInputStream
      * @return PakHeader
      * @throws Exception
      */
      private PakHeader readHeader(DataInputStream dis) throws Exception{
      PakHeader header=new PakHeader();
      char[] signature=readCharArray(dis,PakHeader.SIGNATURE_LENGTH);
      header.setSignature(signature);
      header.setVersion(dis.readFloat());
      header.setNumFileTableEntries(dis.readLong());
      header.setCipherAction(dis.readByte());
      header.setCipherValue(dis.readByte());
      char[] uniqueID=readCharArray(dis,PakHeader.UNIQUEID_LENGTH);
      header.setUniqueID(uniqueID);
      header.setReserved(dis.readLong());
      return header;
      }
      /**
      * 讀取所有的文件table
      * @param dis DataInputStream
      * @param fileTableNumber 文件表總數(shù)
      * @return 文件table數(shù)組
      * @throws Exception
      */
      private PakFileTable[] readFileTable(DataInputStream dis,int fileTableNumber) throws Exception{
      PakFileTable[] fileTable=new PakFileTable[fileTableNumber];
      for(int i=0;i<fileTableNumber;i++){
      PakFileTable ft=new PakFileTable();
      ft.setFileName(readCharArray(dis,PakFileTable.FILENAME_LENGTH));
      ft.setFileSize(dis.readLong());
      ft.setOffSet(dis.readLong());
      fileTable[i]=ft;
      }        
      return fileTable;
      }
      /**
      * 從pak文件讀取文件到byte數(shù)組
      * @param dis DataInputStream
      * @param fileTable PakFileTable
      * @return byte數(shù)組
      * @throws Exception
      */
      private byte[] readFileFromPak(DataInputStream dis,PakHeader header,PakFileTable fileTable) throws Exception{
      dis.skip(fileTable.getOffSet()-workOutOffsetStart(header));
      //
      int fileLength=(int)fileTable.getFileSize();
      byte[] fileBuff=new byte[fileLength];
      int readLength=dis.read(fileBuff,0,fileLength);
      if (readLength<fileLength){
      System.out.println("讀取數(shù)據(jù)長(zhǎng)度不正確");
      return null;
      }
      else{
      decryptBuff(fileBuff,readLength,header);
      return fileBuff;
      }
      }
      /**
      * 將buffer中的內(nèi)容寫(xiě)入到文件
      * @param fileBuff 保存文件內(nèi)容的buffer
      * @param fileName 文件名
      * @param extractDir 文件導(dǎo)出目錄
      * @throws Exception
      */
      private void writeFileFromByteBuffer(byte[] fileBuff,String fileName,String extractDir) throws Exception{
      String extractFilePath=extractDir+fileName;
      File wFile=new File(extractFilePath);
      FileOutputStream fos=new FileOutputStream(wFile);
      DataOutputStream dos=new DataOutputStream(fos);
      dos.write(fileBuff);
      dos.close();
      fos.close();
      }
      /**
      * 從pak文件中取出指定的文件到byte數(shù)組,如果需要的話可以將byte數(shù)組寫(xiě)為文件
      * @param pakFilePath pak文件路徑
      * @param extractFileName pak文件中將要被取出的文件名
      * @param writeFile 是否需要將byte數(shù)組寫(xiě)為文件
      * @param extractDir 如果需要的話可以將byte數(shù)組寫(xiě)為文件,extractDir為取出數(shù)據(jù)被寫(xiě)的目錄文件
      * @return byte數(shù)組
      * @throws Exception
      */
      public byte[] extractFileFromPak(String pakFilePath,
      String extractFileName,boolean writeFile,String extractDir) throws Exception{
      File rFile=new File(pakFilePath);
      FileInputStream fis=new FileInputStream(rFile);
      DataInputStream dis=new DataInputStream(fis);
      PakHeader header=readHeader(dis);
      PakFileTable[] fileTable=readFileTable(dis,(int)header.getNumFileTableEntries());
      boolean find=false;        int fileIndex=0;
      for(int i=0;i<fileTable.length;i++){
      String fileName=new String(fileTable[i].getFileName()).trim();
      if (fileName.equals(extractFileName)){
      find=true;
      fileIndex=i;
      break;
      }
      }
      if (find==false){
      System.out.println("沒(méi)有找到指定的文件");
      return null;        
      }      
      else{
      byte[] buff=readFileFromPak(dis,header,fileTable[fileIndex]);
      if (writeFile){
      writeFileFromByteBuffer(buff,extractFileName,extractDir);
      }            
      else{
      dis.close();
      fis.close();
      }
      return buff;
      }
      }
      /**
      * 從pak文件中取出指定的Pak文件的信息
      * @param pakFilePath pak文件路徑
      * @return 裝載文件頭和文件table數(shù)組的Vector
      * @throws Exception
      */
      public Vector showPakFileInfo(String pakFilePath) throws Exception{
      File rFile=new File(pakFilePath);
      FileInputStream fis=new FileInputStream(rFile);
      DataInputStream dis=new DataInputStream(fis);
      PakHeader header=readHeader(dis);
      PakFileTable[] fileTable=readFileTable(dis,(int)header.getNumFileTableEntries());        Vector result=new Vector();
      result.add(header);
      result.add(fileTable);
      return result;
      }
      public static void main(String[] argv) throws Exception{
      PakUtil pu=new PakUtil();
      //構(gòu)造文件頭
      char[] signature=new char[PakHeader.SIGNATURE_LENGTH];
      signature=new String("012345").toCharArray();
      char[] uniqueID=new char[PakHeader.UNIQUEID_LENGTH];
      uniqueID=new String("0123456789").toCharArray();
      PakHeader header=new PakHeader();
      header.setSignature(signature);
      header.setNumFileTableEntries(3);
      header.setCipherAction((byte)PakHeader.ADDITION_CIPHERACTION);
      header.setCipherValue((byte)0x0f);
      header.setUniqueID(uniqueID);
      header.setVersion(1.0f);
      header.setReserved(0L);
      String[] filePathArray={"F:\\eclipse3.1RC3\\workspace\\gmatrixProject_j2se\\testFiles\\apple.png",
      "F:\\eclipse3.1RC3\\workspace\\gmatrixProject_j2se\\testFiles\\cushaw.png",
      "F:\\eclipse3.1RC3\\workspace\\gmatrixProject_j2se\\testFiles\\flash.png"};
      String extractFilePath="F:\\eclipse3.1RC3\\workspace\\gmatrixProject_j2se\\testFiles\\test.pak";
      //制作Pak文件
      System.out.println("制作Pak文件...");
      pu.makePakFile(filePathArray,extractFilePath,header);
      System.out.println("制作Pak文件完成");
      //從Pak文件中取出所有的圖片文件
      Vector pakInfo=pu.showPakFileInfo(extractFilePath);
      header=(PakHeader)pakInfo.elementAt(0);
      System.out.println("Pak文件信息:");
      System.out.println("文件頭:");
      System.out.println(header);
      PakFileTable[] fileTable=(PakFileTable[])pakInfo.elementAt(1);
      for(int i=0;i<fileTable.length;i++){
      System.out.println("文件table["+i+"]:");
      System.out.println(fileTable[i]);
      }
      String restoreDir="F:\\eclipse3.1RC3\\workspace\\gmatrixProject_j2se\\testFiles\\extract\\";
      String restoreFileName=null;
      byte[] fileBuff=null;
      for(int i=0;i<fileTable.length;i++){
      restoreFileName=new String(fileTable[i].getFileName()).trim();
      System.out.println("從Pak文件中取出"+restoreFileName+"文件...");
      fileBuff=pu.extractFileFromPak(extractFilePath,restoreFileName,true,restoreDir);
      System.out.println("從Pak文件中取出"+restoreFileName+"文件保存在"+restoreDir+"目錄");
      }
      }}
      
      七、PakUtil類(j2me版):
      
      PakUtil.java
      package cn.org.matrix.gmatrix.gameLab.util.pak;
      import java.io.*;
      import java.util.Vector;
      /** * Pak工具類 * 功能: * 從Pak文件中取出png圖片,構(gòu)造byte數(shù)組(可以用來(lái)構(gòu)造Image對(duì)象) * @author cleverpig * */public class PakUtil {
      public PakUtil(){
      }
      /**
      * 計(jì)算文件位移的起始點(diǎn)
      * @return 文件位移的起始點(diǎn)
      */
      private long workOutOffsetStart(PakHeader header){
      //計(jì)算出文件頭+文件table的長(zhǎng)度
      return PakHeader.size()+header.getNumFileTableEntries()*PakFileTable.size();
      }
      /**
      * 從DataInputStream讀取char數(shù)組
      * @param dis DataInputStream
      * @param readLength 讀取長(zhǎng)度
      * @return char數(shù)組
      * @throws Exception
      */
      private char[] readCharArray(DataInputStream dis,int readLength) throws Exception{
      char[] readCharArray=new char[readLength];
      for(int i=0;i<readLength;i++){
      readCharArray[i]=dis.readChar();
      }
      return readCharArray;
      }
      /**
      * 從PAK文件中讀取文件頭
      * @param dis DataInputStream
      * @return PakHeader
      * @throws Exception
      */
      private PakHeader readHeader(DataInputStream dis) throws Exception{
      PakHeader header=new PakHeader();
      char[] signature=readCharArray(dis,PakHeader.SIGNATURE_LENGTH);
      header.setSignature(signature);
      header.setVersion(dis.readFloat());
      header.setNumFileTableEntries(dis.readLong());
      header.setCipherAction(dis.readByte());
      header.setCipherValue(dis.readByte());
      char[] uniqueID=readCharArray(dis,PakHeader.UNIQUEID_LENGTH);
      header.setUniqueID(uniqueID);
      header.setReserved(dis.readLong());
      return header;
      }
      /**
      * 讀取所有的文件table
      * @param dis DataInputStream
      * @param fileTableNumber 文件表總數(shù)
      * @return 文件table數(shù)組
      * @throws Exception
      */
      private PakFileTable[] readFileTable(DataInputStream dis,int fileTableNumber) throws Exception{
      PakFileTable[] fileTable=new PakFileTable[fileTableNumber];
      for(int i=0;i<fileTableNumber;i++){
      PakFileTable ft=new PakFileTable();
      ft.setFileName(readCharArray(dis,PakFileTable.FILENAME_LENGTH));
      ft.setFileSize(dis.readLong());
      ft.setOffSet(dis.readLong());
      fileTable[i]=ft;
      }
      return fileTable;
      }
      /**
      * 從pak文件讀取文件到byte數(shù)組
      * @param dis DataInputStream
      * @param fileTable PakFileTable
      * @return byte數(shù)組
      * @throws Exception
      */    
      private byte[] readFileFromPak(DataInputStream dis,PakHeader header,PakFileTable fileTable) throws Exception{
      dis.skip(fileTable.getOffSet()-workOutOffsetStart(header));
      //
      int fileLength=(int)fileTable.getFileSize();
      byte[] fileBuff=new byte[fileLength];
      int readLength=dis.read(fileBuff,0,fileLength);
      if (readLength<fileLength){
      System.out.println("讀取數(shù)據(jù)長(zhǎng)度不正確");
      return null;
      }
      else{
      decryptBuff(fileBuff,readLength,header);
      }        
      return fileBuff;
      }
      /**
      * 使用文件頭中的密碼對(duì)數(shù)據(jù)進(jìn)行解密
      * @param buff 被解密的數(shù)據(jù)
      * @param buffLength 數(shù)據(jù)的長(zhǎng)度
      * @param header 文件頭
      */
      private void decryptBuff(byte[] buff,int buffLength,PakHeader header){
      for(int i=0;i<buffLength;i++){
      switch(header.getCipherAction()){
      case PakHeader.ADDITION_CIPHERACTION:
      buff[i]-=header.getCipherValue();
      break;
      case PakHeader.SUBTRACT_CIHOERACTION:
      buff[i]+=header.getCipherValue();
      break;
      }
      }
      }
      /**
      * 從pak文件中取出指定的文件到byte數(shù)組
      * @param pakResourceURL pak文件的資源路徑
      * @param extractResourceName pak文件中將要被取出的文件名
      * @return byte數(shù)組    
      * @throws Exception
      */    
      public byte[] extractResourceFromPak(String pakResourceURL
      ,String extractResourceName) throws Exception{
      InputStream is=this.getClass().getResourceAsStream(pakResourceURL);
      DataInputStream dis=new DataInputStream(is);
      PakHeader header=readHeader(dis);//
      System.out.println("文件頭:");//
      System.out.println(header);
      PakFileTable[] fileTable=readFileTable(dis,(int)header.getNumFileTableEntries());//
      for(int i=0;i<fileTable.length;i++){//
      System.out.println("文件table["+i+"]:");//
      System.out.println(fileTable[i]);//
      }
      boolean find=false;
      int fileIndex=0;
      for(int i=0;i<fileTable.length;i++){
      String fileName=new String(fileTable[i].getFileName()).trim();
      if (fileName.equals(extractResourceName)){
      find=true;
      fileIndex=i;
      break;
      }
      }
      if (find==false){
      System.out.println("沒(méi)有找到指定的文件");
      return null;
      }
      else{
      byte[] buff=readFileFromPak(dis,header,fileTable[fileIndex]);
      return buff;
      }
      }
      /**
      * 從pak文件中取出指定的Pak文件的信息
      * @param pakResourcePath pak文件資源路徑
      * @return 裝載文件頭和文件table數(shù)組的Vector
      * @throws Exception
      */
      public Vector showPakFileInfo(String pakResourcePath) throws Exception{
      InputStream is=this.getClass().getResourceAsStream(pakResourcePath);
      DataInputStream dis=new DataInputStream(is);
      PakHeader header=readHeader(dis);
      PakFileTable[] fileTable=readFileTable(dis,(int)header.getNumFileTableEntries());
      Vector result=new Vector();
      result.addElement(header);
      result.addElement(fileTable);
      return result;
      }
      public static void main(String[] argv) throws Exception{
      PakUtil pu=new PakUtil();
      String extractResourcePath="/test.pak";
      //從Pak文件中取出所有的圖片文件
      Vector pakInfo=pu.showPakFileInfo(extractResourcePath);
      PakHeader header=(PakHeader)pakInfo.elementAt(0);
      System.out.println("Pak文件信息:");
      System.out.println("文件頭:");
      System.out.println(header);
      PakFileTable[] fileTable=(PakFileTable[])pakInfo.elementAt(1);
      for(int i=0;i<fileTable.length;i++){
      System.out.println("文件table["+i+"]:");
      System.out.println(fileTable[i]);
      }
      String restoreFileName=null;       
      byte[] fileBuff=null;
      for(int i=0;i<fileTable.length;i++){
      restoreFileName=new String(fileTable[i].getFileName()).trim();
      System.out.println("從Pak文件中取出"+restoreFileName+"文件數(shù)據(jù)...");
      fileBuff=pu.extractResourceFromPak(extractResourcePath,restoreFileName);
      System.out.println("從Pak文件中取出"+restoreFileName+"文件數(shù)據(jù)完成");
      }   
       }}
      
      八、源代碼使用簡(jiǎn)介:
      
      Pak過(guò)程:j2se版的PakUtil將testFiles目錄中的三個(gè)png文件Pak成為test.pak文件。
      UnPak過(guò)程:j2se版的PakUtil將testFiles目錄中test.pak文件釋放到testFiles\extract目錄下;j2me版的PakUtil從res目錄中的test.pak文件讀取出其中所包含的3個(gè)png文件數(shù)據(jù)并裝入到byte數(shù)據(jù),用來(lái)構(gòu)造Image對(duì)象,大家請(qǐng)運(yùn)行PakUtilTestMIDlet.java便可看到輸出的信息。
    posted on 2007-02-13 17:23 SIMONE 閱讀(448) 評(píng)論(0)  編輯  收藏 所屬分類: 收藏
    主站蜘蛛池模板: 亚洲va久久久噜噜噜久久 | 国产午夜免费福利红片| 日韩一区二区三区免费播放| 免费视频精品一区二区| 欧洲亚洲国产精华液| 日韩毛片免费一二三| 免费成人在线电影| 国产在线精品一区免费香蕉| 99精品在线免费观看| 黄瓜视频高清在线看免费下载| 日韩免费无码视频一区二区三区| 在线观看人成视频免费无遮挡| 一级特黄色毛片免费看| 无套内射无矿码免费看黄| 99精品免费视品| 国产a视频精品免费观看| 国产精品va无码免费麻豆| 亚洲日韩精品一区二区三区无码 | 亚洲中文字幕日本无线码| 亚洲天堂2016| 免费又黄又爽又猛大片午夜| 国产精品免费看久久久 | 亚洲av无码专区在线电影| 一级毛片视频免费| 最近免费最新高清中文字幕韩国| 99久久99久久免费精品小说| 免费黄色app网站| 国产精品免费一级在线观看| 国产亚洲人成网站观看| 亚洲AV永久无码精品一百度影院| 久久夜色精品国产亚洲AV动态图 | 亚洲国产精品成人久久蜜臀 | 亚洲一卡一卡二新区无人区| 亚洲色丰满少妇高潮18p| 久久久久久久国产免费看| 一级毛片在线完整免费观看| 3d动漫精品啪啪一区二区免费| h在线观看视频免费网站| 国产一级特黄高清免费大片| 亚洲avav天堂av在线不卡| 国产精品亚洲小说专区|