当前位置: 移动技术网 > IT编程>开发语言>Java > Java实现较大二进制文件的读、写方法

Java实现较大二进制文件的读、写方法

2019年07月22日  | 移动技术网IT编程  | 我要评论
由于项目需要,需要对二进制文件进行读写、转换。 文件说明:由其他程序得到的二进制文件,文件内容为:包含23543个三角形、13270个顶点的三角网所对应的721组流速矢量

由于项目需要,需要对二进制文件进行读写、转换。

文件说明:由其他程序得到的二进制文件,文件内容为:包含23543个三角形、13270个顶点的三角网所对应的721组流速矢量(u、v)文件,通俗些说,一条数据包含两个双精度型的数值,每组数组包含23543条数据,如果以一个双精度数值为单位,则总共有23543 * 721 * 2 =33,949,006条数据。由fortran程序以每 8 byte存储一个数值的二进制文件存储,最终文件大小为下图所示:

              

测试:从该文件读出数据之后,转换为十进制,存储到另一个文件中。

/**
 * 针对大文件存储,请依次调用beginsave、addsave、endsave。
 * 
 * @author ck
 *
 */
public class datautil {

  dataoutputstream binaryout=null;
  bufferedwriter textout=null;
  string filepath=null;
  enum savefiletype{text,binary};
  savefiletype savefiletype;

  /**
   * double转byte[]
   * 
   * @param d
   * @return
   */
  public static byte[] double2bytes(double d) {
    long value = double.doubletorawlongbits(d);
    byte[] byteret = new byte[8];
    for (int i = 0; i < 8; i++) {
      byteret[i] = (byte) ((value >> 8 * i) & 0xff);
    }
    return byteret;
  }

  /**
   * byte[]转double
   * 
   * @param arr
   * @return
   */
  public static double bytes2double(byte[] arr) {
    long value = 0;
    for (int i = 0; i < 8; i++) {
      value |= ((long) (arr[i] & 0xff)) << (8 * i);
    }
    return double.longbitstodouble(value);
  }
  /**
   * 大型数据存储之开始存储
   * @param filepath 文件路径
   * @param savefiletype 保存的文件类型,文本文件、双精度所存的二进制文件
   * @return
   * @throws ioexception
   */
  public boolean beginsave(string filepath,savefiletype savefiletype) throws ioexception {
    if (filepath == "" || filepath == null) {
      system.out.println("the savepath is null.");
      return false;
    }
    this.filepath=filepath;
    this.savefiletype=savefiletype;
    file datafile = new file(filepath);
    if (!datafile.getparentfile().exists()) {
      datafile.getparentfile().mkdirs();
    }
    if (datafile.exists()) {
      datafile.delete();
    }
    datafile.createnewfile();
    switch(this.savefiletype){
    case text:
      textout= new bufferedwriter(new filewriter(datafile,true));
      break;
    case binary:
      binaryout = new dataoutputstream(new fileoutputstream(datafile,true));
      break;
    default:
      break;
      
    }    
    return true;
  }
/**
 * 大型文件存储之追加存储
 * @param datastr 若是文本存储则无要求,若是双精度的二进制文件,以若干空格隔开
 * @return
 * @throws ioexception
 */
  public boolean addsave(string datastr) throws ioexception{
    switch(this.savefiletype){
    case text:
      this.textout.append(datastr);
      break;
    case binary:
      datastr=datastr.trim();
      string[] dataarray=datastr.split("\\s+");
      for(int i=0;i<dataarray.length;i++){
        this.binaryout.write(double2bytes(double.parsedouble(dataarray[i])));
      }          
      break;
    default:
      break;
    
    }
    
    return true;
  }
  /**
   * 大型文件存储之结束保存,清空缓存、关闭文件。
   * @return
   * @throws ioexception
   */
  public boolean endsave() throws ioexception{
    switch(this.savefiletype){
    case text:
      this.textout.flush();
      this.textout.close();
      break;
    case binary:
      this.binaryout.flush();
      this.binaryout.close();
      break;
    default:
      break;    
    }
    
    return true;
  }
 /**
   * 将字符串保存为文本文件(一次完成)
   * 
   * @param datastr
   *      文件内容
   * @param savepath
   *      文件路径,包含文件名、后缀
   * @return
   * @throws ioexception
   */
  public boolean savetextfile(string datastr, string savepath)
      throws ioexception {
    if (datastr == "" || datastr == null) {
      system.out.println("the datastr is null.");
      return false;
    }
    if (savepath == "" || savepath == null) {
      system.out.println("the savepath is null.");
      return false;
    }
    file datafile = new file(savepath);
    if (!datafile.getparentfile().exists()) {
      datafile.getparentfile().mkdirs();
    }
    if (datafile.exists()) {
      datafile.delete();
    }
    datafile.createnewfile();
    bufferedwriter out;

    out = new bufferedwriter(new filewriter(datafile));

    out.append(datastr);
    out.flush();
    out.close();

    return true;
  }

  /**
   * 双精度存为二进制数据(一次存储)
   * 
   * @param datastr 双精度数据组成的字符串,以若干空格隔开
   * @param outputpath
   * @return
   * @throws ioexception
   */
  public boolean savebinaryfile(string datastr, string outputpath) throws ioexception {

    if (datastr == "" || datastr == null) {
      system.out.println("the datastr is null.");
      return false;
    }
    if (outputpath == "" || outputpath == null) {
      system.out.println("the outputpath is null.");
      return false;
    }
    file datafile = new file(outputpath);

    if (!datafile.getparentfile().exists()) {
      datafile.getparentfile().mkdirs();
    }
    if (datafile.exists()) {
      datafile.delete();
    }
    datafile.createnewfile();
    dataoutputstream out;
    out = new dataoutputstream(new fileoutputstream(datafile));
    // 数据处理
    datastr=datastr.trim();
    string[] dataarray=datastr.split("\\s+");
    for(int i=0;i<dataarray.length;i++){
      out.write(double2bytes(double.parsedouble(dataarray[i])));
    }    
    out.flush();
    out.close();
    return true;

  }
}

代码说明:其中byte[]与double互转为在互联网上查到的方法,具体是哪位大神的我忘记了,在这里为了记录就贴出来啦,上述代码包含了处理小型文件时,将所有内容存在缓存中,之后再一次性写入文本文件、二进制文件中的方法,还包含了对较大型文件的读写方法,下面是自己的一个读写测试。

/**
 * 测试二进制大文件读写(200m左右)
 * @author ck
 *
 */
public class filetest {
  static string inputfilepath=""; //输入文件路径,包含文件名后缀
  static string outputfilepath=""; //输出文件名,包含文件名后缀
  
  public static void file2file() throws ioexception{
    datautil datautil=new datautil(); 
     datainputstream br=new datainputstream( 
         new bufferedinputstream( 
         new fileinputstream(inputfilepath))); 
        datautil.beginsave(outputfilepath, savefiletype.text); //初始化,创建文件,采用文件追加存储的思路
         byte[] onedata=new byte[8];
         int i=0,count =0 ;
        while(br.read(onedata, 0, 8)!=-1){  
          i=i+1;
          datautil.addsave(string.valueof(datautil.bytes2double(onedata)));          
          if(i/23543==0){
            count++;
            system.out.println(count+"\n");

          }
        }
        datautil.endsave();    //将还在缓存中的数据写入到文件中,关闭文件。 
  }
}

 此次测试代码很快就run完了,但是输出文件的生成大概用了近半分钟(刻意秒表计时了一次),尝试用一次性读写的办法,卡很久,也没有出结果。所得的十进制文本文件,大小为这么多:

我想,原来fortran程序作者的初衷应该是觉得二进制存储比十进制节省空间吧,事实上也确实节省了一半多的空间。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网