服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

j2me技术――跟我学制作pak文件


  序言:
  
  由于前些时间,一些matrixer常问关于j2me中使用pak文件的问题。本人虽学艺不深,但满怀热心的做了一番探索,现将制作pak文件的看法和方法公布出来,大家多多提意见。
  
  一、什么是pak文件
  
  pak文件就是将多个文件打包为一个单独文件,在这个文件中保存着多个文件的数据,当然还有一些描述文件结构的数据。所以将“pak”作为文件的后缀是一种常规的用法,大家可以自定义其它的文件后缀。
  
  二、为什么使用pak文件:
  
  由于midp对发布安装的j2me程序大小进行了限制,所以缩小发布程序就意味着能够提供更多的程序或者内容(如图片、音乐)给用户。而通过研究发现zip/jar算法对大文件的压缩率高于对等量的多个小文件的压缩率。
  
  当然还有其它方法,这里简单做一下讨论比如使用混淆器proguard的“-overloadaggressively”选项使jar文件缩小,但也会导致一些错误,因为这种方法生成jar中的class符合java byte code标准,但是与java语法相悖,严重的可能造成一些jre对object的序列化错误。
  
  所以使用pak方法将程序中要用到的资源(图片、音乐、文本)组合为单一文件是一个安全有效的方法。而且对于一些商用程序,完全可以在pak文件中对文件数据进行加密,很好的保护了作者和公司的权益。本人的sample中使用了简单的“加减法”加密,对于手机这类设备来讲是一个效率较高的选择。
  
  三、pak文件的结构:
  
  大家可以自己设计pak文件结构,本人这里只是抛砖引玉的作个sample。下面就是本人设计的pak文件结构:
  
  pak file header:pak文件的头部
  
  * 签名:6字节char数组 * 版本号:32位float * 文件table数量:32位整数 * 密码行为:8位字节 * 密码:8位字节 * 文件唯一id:10字节char数组 * 保留位:32位整数(4字节)
  
  file table:pak文件中包含文件的列表,在一个pak文件中一个被包含的文件对应一个file table。
  
  * 文件名:30字节char数组 * 文件大小:32位整型 * 文件在pak文件中的位移:32位整数
  
  concatenated file data:按file table的顺序连接在一起的文件数据。
  * 文件数据
  
  四、程序框架:
  
  说明:由于pak文件的制作和使用分别要使用两个java应用领域:j2se和j2me,所以本人将pakutil类制作了2个版本(j2se和j2me)。
  
  程序框架如下:
  1。pakheader类,定义了pak文件头。
  2。pakfiletable类,定义pak文件table。
  3。pakutil类(j2se版),具备两个功能:将多个png图片合成一个pak文件,并使用简单的加减加密法对其进行加密;从pak文件中取出png图片,构造byte数组(可以用来构造image对象)或者写为文件。
  pakutil类(j2me版),具备的功能:从pak文件中取出png图片,构造byte数组(可以用来构造image对象)。
  
  五、pakheader和pakfiletable类
  
  pakheader.java:
  package cn.org.matrix.gmatrix.gamelab.util.pak;/** * pak文件头: * 结构: *
  签名:6字节char数组 *  版本号:32位float *
  文件table数量:32位整数 *
  密码行为:8位字节 *  密码:8位字节 *
  文件唯一id:10字节char数组 *
  保留位:32位整数(4字节) * @author cleverpig * */class pakheader {
  //定义文件唯一id长度
  public static final int uniqueid_length=10;
  //定义文件签名长度
  public static final int signature_length=6;
  //定义加法运算
  public static final int addition_cipheraction=0;
  //定义减法运算
  public static final int subtract_cihoeraction=1;
  //文件签名
  private char[] signature=new char[signature_length];
  //版本号
  private float version=0f;
  //文件table数量
  private long numfiletableentries=0;
  //密码使用方法:在原数据上进行加法还是减法
  private byte cipheraction=addition_cipheraction;
  //密码值
  private byte ciphervalue=0x00;
  //唯一id
  private char[] uniqueid=new char[uniqueid_length];
  //保留的4字节
  private long reserved=0;
  public pakheader(){
  }
  /**
  * 构造方法
  * @param signature 签名
  * @param version 版本
  * @param numfiletableentries 文件table数量
  * @param cipheraction 密码使用方法
  * @param ciphervalue 密码值
  * @param uniqueid 唯一id
  * @param reserved 保留的2字节
  */
  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版本号:"+this.version
  +"/t文件table数量:"+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结构: *
  文件名:30字节char数组 *
  文件大小:32位整型 *
  文件在pak文件中的位移:32位整数 * @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(){
  }
  /**
  * 构造方法
  * @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.将多个png图片合成一个pak文件,并使用简单的加减加密法对其进行加密;
  * 2.从pak文件中取出png图片,构造byte数组(可以用来构造image对象)或者写为文件 * @author cleverpig * */public class pakutil {
  public pakutil(){
  }
  /**
  * 返回文件长度
  * @param filepath 文件路径
  * @return 文件长度
  */
  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();
  }
  /**
  * 计算文件位移的起始点
  * @return 文件位移的起始点
  */
  private long workoutoffsetstart(pakheader header){
  //计算出文件头+文件table的长度
  return pakheader.size()+header.getnumfiletableentries()*pakfiletable.size();
  }
  /**
  * 计算文件位移
  * @param fileindex 文件序号
  * @param lastfileoffset 上一个文件位移
  * @return 文件在pak文件中的位移
  */
  private long workoutnextoffset(long sourcefilesize,long lastfileoffset){
  return lastfileoffset+sourcefilesize;    
  }
  /**
  * 生成文件table
  * @param sourcefilename 源文件名
  * @param sourcefilesize 源文件长度
  * @param currentfileoffset 当前文件位移
  * @return 生成的pakfiletable对象
  */    
  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字符数组写入到dataoutputstream中
  * @param towritechararray 被写入的char数组
  * @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++);
  }        
  /**
  * 使用文件头中的密码对数据进行加密
  * @param buff 被加密的数据
  * @param bufflength 数据的长度
  * @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;
  }
  }
  }
  /**
  * 使用文件头中的密码对数据进行解密
  * @param buff 被解密的数据
  * @param bufflength 数据的长度
  * @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 源文件路径数组
  * @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];
  //计算文件位移起始点
  long fileoffset=workoutoffsetstart(header);
  //逐个建立文件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);
  //计算下一个文件位移
  fileoffset=workoutnextoffset(sourcefilesize,fileoffset);
  filetable[i]=ft;
  }
  //写入文件头
  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());
  //写入文件table
  for(int i=0;i<filetable.length;i++){
  writechararray(filetable[i].getfilename(),dos);
  dos.writelong(filetable[i].getfilesize());
  dos.writelong(filetable[i].getoffset());
  }
  //写入文件数据
  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数组     * @param dis datainputstream
  * @param readlength 读取长度
  * @return char数组
  * @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 文件表总数
  * @return 文件table数组
  * @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数组
  * @param dis datainputstream
  * @param filetable pakfiletable
  * @return byte数组
  * @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("读取数据长度不正确");
  return null;
  }
  else{
  decryptbuff(filebuff,readlength,header);
  return filebuff;
  }
  }
  /**
  * 将buffer中的内容写入到文件
  * @param filebuff 保存文件内容的buffer
  * @param filename 文件名
  * @param extractdir 文件导出目录
  * @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数组,如果需要的话可以将byte数组写为文件
  * @param pakfilepath pak文件路径
  * @param extractfilename pak文件中将要被取出的文件名
  * @param writefile 是否需要将byte数组写为文件
  * @param extractdir 如果需要的话可以将byte数组写为文件,extractdir为取出数据被写的目录文件
  * @return byte数组
  * @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("没有找到指定的文件");
  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数组的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();
  //构造文件头
  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图片,构造byte数组(可以用来构造image对象) * @author cleverpig * */public class pakutil {
  public pakutil(){
  }
  /**
  * 计算文件位移的起始点
  * @return 文件位移的起始点
  */
  private long workoutoffsetstart(pakheader header){
  //计算出文件头+文件table的长度
  return pakheader.size()+header.getnumfiletableentries()*pakfiletable.size();
  }
  /**
  * 从datainputstream读取char数组
  * @param dis datainputstream
  * @param readlength 读取长度
  * @return char数组
  * @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 文件表总数
  * @return 文件table数组
  * @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数组
  * @param dis datainputstream
  * @param filetable pakfiletable
  * @return byte数组
  * @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("读取数据长度不正确");
  return null;
  }
  else{
  decryptbuff(filebuff,readlength,header);
  }        
  return filebuff;
  }
  /**
  * 使用文件头中的密码对数据进行解密
  * @param buff 被解密的数据
  * @param bufflength 数据的长度
  * @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数组
  * @param pakresourceurl pak文件的资源路径
  * @param extractresourcename pak文件中将要被取出的文件名
  * @return byte数组    
  * @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("没有找到指定的文件");
  return null;
  }
  else{
  byte[] buff=readfilefrompak(dis,header,filetable[fileindex]);
  return buff;
  }
  }
  /**
  * 从pak文件中取出指定的pak文件的信息
  * @param pakresourcepath pak文件资源路径
  * @return 装载文件头和文件table数组的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+"文件数据...");
  filebuff=pu.extractresourcefrompak(extractresourcepath,restorefilename);
  system.out.println("从pak文件中取出"+restorefilename+"文件数据完成");
  }   
   }}
  
  八、源代码使用简介:
  
  pak过程:j2se版的pakutil将testfiles目录中的三个png文件pak成为test.pak文件。
  unpak过程:j2se版的pakutil将testfiles目录中test.pak文件释放到testfiles/extract目录下;j2me版的pakutil从res目录中的test.pak文件读取出其中所包含的3个png文件数据并装入到byte数据,用来构造image对象,大家请运行pakutiltestmidlet.java便可看到输出的信息。

扫描关注微信公众号