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

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

文件说明:由其他程序得到的二进制文件,文件内容为:包含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程序作者的初衷应该是觉得二进制存储比十进制节省空间吧,事实上也确实节省了一半多的空间。

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

(0)

相关推荐

  • Java 中二进制转换成十六进制的两种实现方法

    Java 中二进制转换成十六进制的两种实现方法 每个字节转成16进制,方法1 /** * 每个字节转成16进制,方法1 * * @param result */ private static String toHex(byte[] result) { StringBuffer sb = new StringBuffer(result.length * 2); for (int i = 0; i < result.length; i++) { sb.append(Character.forDigi

  • java实现插入mysql二进制文件,blob类型,遇到问题及解决办法

    首先是数据库建立要准备的: 我们要把放置二进制字段设置为Blob类型,根据文件的大小选择合适的Blob类型,一下是各个Blob类型所能容纳二进制文件的大小 MySQL的四种BLOB类型 类型 大小(单位:字节) TinyBlob 最大 255 Blob 最大 65K MediumBlob 最大 16M LongBlob 最大 4G 一下是具体操作代码: 复制代码 代码如下: /** * * 把二进制文件(该二进制文件可以是本地硬盘路径,也可以是一个网络路径)存入数据库 * create date

  • Java字符串转成二进制码的方法

    Java将字符串转成二进制码,具体内容如下 public void toBinary(){ String str = "王雪"; char[] strChar=str.toCharArray(); String result=""; for(int i=0;i<strChar.length;i++){ result +=Integer.toBinaryString(strChar[i])+ " "; } System.out.println

  • JAVA中读取文件(二进制,字符)内容的几种方法总结

    JAVA中读取文件内容的方法有很多,比如按字节读取文件内容,按字符读取文件内容,按行读取文件内容,随机读取文件内容等方法,本文就以上方法的具体实现给出代码,需要的可以直接复制使用 public class ReadFromFile { /** * 以字节为单位读取文件,常用于读二进制文件,如图片.声音.影像等文件. */ public static void readFileByBytes(String fileName) { File file = new File(fileName); In

  • 利用Java读取二进制文件实例详解

    前言 本文主要给大家介绍了关于Java读取二进制文件的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 读Hex写CSV data目录下有little-endian bin文件,2个字节代表一个数字. bin存储的数据格式可自己定义.相同的方法可以直接应用到Android中. `-- networkProj |-- data |-- networkProj.iml |-- out `-- src 实现方法 private static void convertFiles

  • java数据类型与二进制详细介绍

    java数据类型与二进制详细介绍 在java中 Int 类型的变量占 4个字节 Long 类型的变量占8个字节 一个程序就是一个世界,变量是这个程序的基本单位. Java基本数据类型 1.        整数类型 2.        小数(浮点数)类型 3.        布尔类型 4.        字符类型 整数类型 整数类型可以表示一个整数,常用的整数类型有:byte,short,int,long Byte  一个字节  -128到127 注:0有两个表示0000 0000正零  1000

  • java 判断二进制文件的方法

    java 判断二进制文件的方法 直接上代码,实现方法很简单: 代码实现: public static boolean isBinary(File file) { boolean isBinary = false; try { FileInputStream fin = new FileInputStream(file); long len = file.length(); for (int j = 0; j < (int) len; j++) { int t = fin.read(); if (

  • 详谈Java中的二进制及基本的位运算

    二进制是计算技术中广泛采用的一种数制.二进制数据是用0和1两个数码来表示的数.它的基数为2,进位规则是"逢二进一",借位规则是"借一当二",由18世纪德国数理哲学大师莱布尼兹发现.当前的计算机系统使用的基本上是二进制系统,数据在计算机中主要是以补码的形式存储的.计算机中的二进制则是一个非常微小的开关,用"开"来表示1,"关"来表示0. 那么Java中的二进制又是怎么样的呢?让我们一起来揭开它神秘的面纱吧. 一.Java内置的进

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

    由于项目需要,需要对二进制文件进行读写.转换. 文件说明:由其他程序得到的二进制文件,文件内容为:包含23543个三角形.13270个顶点的三角网所对应的721组流速矢量(u.v)文件,通俗些说,一条数据包含两个双精度型的数值,每组数组包含23543条数据,如果以一个双精度数值为单位,则总共有23543 * 721 * 2 =33,949,006条数据.由Fortran程序以每 8 Byte存储一个数值的二进制文件存储,最终文件大小为下图所示: 测试:从该文件读出数据之后,转换为十进制,存储到另

  • 简单的用java实现读/写文本文件的示例

    /*    * 简单的读/写文本文件的示例    * 这里包含了三个例子,即    * 1. 将文件读入到内存(这里是StringBuffer)的例子    * 2. 将内容中的文本写到文件    * 3. 将一个文件的内容读出来写入另一个文件中    *    同时也展示了如果从输入流中读出来内容写入输出流中(仅限文本流)    * 三个例子可以独立存在,所以根据需要只看其中一个就行了.    */ import java.io.BufferedReader;    import java.i

  • Java实现生产者消费者问题与读者写者问题详解

    1.生产者消费者问题 生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品.解决生产者/消费者问题的方法可分为两类:(1)采用某种机制保护生产者和消费者之间的同步:(2)在生产者和消费者之间建立一个管道.第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式.第二种管道缓冲区不易控制,被传输数据对象不易于封装等,实用性不强. 同步问题核心在于:如何保证同一资源被多个线程并发访问时的完整性.常

  • Java内存映射 大文件轻松处理

    前言 内存映射文件(Memory-mapped File),指的是将一段虚拟内存逐字节映射于一个文件,使得应用程序处理文件如同访问主内存(但在真正使用到这些数据前却不会消耗物理内存,也不会有读写磁盘的操作),这要比直接文件读写快几个数量级. 稍微解释一下虚拟内存(很明显,不是物理内存),它是计算机系统内存管理的一种技术.像施了妖法一样使得应用程序认为它拥有连续的可用的内存,实际上呢,它通常是被分隔成多个物理内存的碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换. 内存映射文件主要的

  • Java高效读取大文件实例分析

    1.概述 本教程将演示如何用Java高效地读取大文件.Java--回归基础. 2.在内存中读取 读取文件行的标准方式是在内存中读取,Guava和ApacheCommonsIO都提供了如下所示快速读取文件行的方法: Files.readLines(new File(path), Charsets.UTF_8); FileUtils.readLines(new File(path)); 这种方法带来的问题是文件的所有行都被存放在内存中,当文件足够大时很快就会导致程序抛出OutOfMemoryErro

  • java高效实现大文件拷贝功能

    在java中,FileChannel类中有一些优化方法可以提高传输的效率,其中transferTo( )和 transferFrom( )方法允许将一个通道交叉连接到另一个通道,而不需要通过一个缓冲区来传递数据.只有FileChannel类有这两个方法,因此 channel-to-channel 传输中通道之一必须是 FileChannel.不能在sock通道之间传输数据,不过socket 通道实现WritableByteChannel 和 ReadableByteChannel 接口,因此文件

  • Java使用POI导出大数据量Excel的方法

    今天需要写一个导出的Excel的功能,但是发现当数据量到3万条时,列数在23列时,内存溢出,CPU使用100%,测试环境直接炸掉.在本地测试时发现,导出3000条左右的数据的时候,堆内存瞬间升高500M左右.然后发现了 SXSSFWorkbook 这个类. 简介 SXSSFWorkbook 需要 poi-ooxml 包 3.8 及以上开始支持,我这边适使用的是 3.9 版本,本质是一个 XSSFWorkbook 类( Excel2007 ),它使用的方式是采用 硬盘空间 来大幅降低 堆内存 的占

  • Java实现excel大数据量导入

    本文实例为大家分享了Java实现excel大数据量导入的具体代码,供大家参考,具体内容如下 情景分析: 通常我们通过poi读取excel文件时,若在用户模式下,由于数据量较大.Sheet较多,很容易出现内存溢出的情况 用户模式读取excel的典型代码如下: FileInputStream file = new FileInputStream("c:\\test.xlsx"); Workbook wb=new XSSFWorkbook(file); 而03版(xls)excel文件每个s

  • Java实现年兽大作战游戏详解

    目录 前言 一.玩法介绍 二.代码介绍 2.1 程序入口[Frame] 2.2 构造器[GamePanel] 2.3 游戏逻辑实现[GamePanel] 2.4 游戏的血液[InitProcessor] 2.5 实体类[FireworksDO][FlowersDO] 2.6 图片素材 三.总结 前言 春节要到了,看惯了前端各种小游戏,确实做得很好,很精致.但是我也要为后端程序员稍微做一点贡献,做一款java版本的[年兽大作战]. 这个游戏加上编写文章,上班摸鱼时间加上回家的空闲时间,大概花了三天

  • 详解处理Java中的大对象的方法

    目录 String中的substring 集合大对象扩容 保持合适的对象粒度 Bitmap 把对象变小 数据的冷热分离 数据双写 写入 MQ 分发 使用 Binlog 同步 思维发散 小结 本文我们将讲解一下对于“大对象”的优化.这里的“大对象”,是一个泛化概念,它可能存放在 JVM 中,也可能正在网络上传输,也可能存在于数据库中. 那么为什么大对象会影响我们的应用性能呢? 第一,大对象占用的资源多,垃圾回收器要花一部分精力去对它进行回收: 第二,大对象在不同的设备之间交换,会耗费网络流量,以及

随机推荐