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程序作者的初衷应该是觉得二进制存储比十进制节省空间吧,事实上也确实节省了一半多的空间。

  恩,此次记录完毕。

时间: 2024-10-06 21:29:17

Java———较大二进制文件的读、写的相关文章

Java IO RandomAccessFile 任意位置读/写

随机读写类 RandomAccessFile的唯一父类是Object,与其他流父类不同.是用来访问那些保存数据记录的文件的,这样你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的. RandomAccessFile是不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系

java并发读&写文件

最近在看Brian Goetz 的<<Java并发实战>>,这本书有两个版本,电子工业出版社的译本很糟糕,建议使用机械工业出版社出版出版的书籍. 在看到第三四章的时候突然想到了多线程读写文件,同时遇到一些书中没有的问题 1, 如何保证组合对象的安全性? 2, 如何判断不变性的约束条件 3, 如何不通过synchronized关键字和锁进行同步处理? 下面是一段代码, 用来从source 读取数据,通过多线程写入target文件中 思路: 1, 如何read/write文件? 2,

java读/写文件

读取文件参考:https://blog.csdn.net/weixin_42129373/article/details/82154471 写入文件参考:https://blog.csdn.net/BanketBoy/article/details/86504704 https://www.cnblogs.com/chenpi/p/5498731.html 1 package text; 2 3 import java.io.BufferedReader; 4 import java.io.Bu

【原创】用JAVA实现大文件上传及显示进度信息

用JAVA实现大文件上传及显示进度信息 ---解析HTTP MultiPart协议 一. 大文件上传基础描述: 各种WEB框架中,对于浏览器上传文件的请求,都有自己的处理对象负责对Http MultiPart协议内容进行解析,并供开发人员调用请求的表单内容. 比如: Spring 框架中使用类似CommonsMultipartFile对象处理表二进制文件信息. 而.NET 中使用HtmlInputFile/ HttpPostedFile对象处理二进制文件信息. 优点:使用框架内置对象可以很方便的

java mysql大数据量批量插入与流式读取分析

总结下这周帮助客户解决报表生成操作的mysql 驱动的使用上的一些问题,与解决方案.由于生成报表逻辑要从数据库读取大量数据并在内存中加工处理后在 生成大量的汇总数据然后写入到数据库.基本流程是 读取->处理->写入. 1 读取操作开始遇到的问题是当sql查询数据量比较大时候基本读不出来.开始以为是server端处理太慢.但是在控制台是可以立即返回数据的.于是在应用 这边抓包,发现也是发送sql后立即有数据返回.但是执行ResultSet的next方法确实阻塞的.查文档翻代码原来mysql驱动默

Java查询大文本文件的处理方法

有时我们需要查询大文本而不是数据库,这时就需要流式读入文件并实现查询算法,还要进行并行处理以提高性能.但JAVA本身缺少相应的类库,需要硬编码才能实现结构化文件计算,代码复杂且可读性差,难以实现高效的并行处理. 使用免费的集算器可以弥补这一不足.集算器封装了丰富的结构化文件读写和游标计算函数,书写简单代码就能实现并行计算,并提供了易用的JDBC接口.JAVA应用程序可以将集算器脚本文件当做数据库存储过程执行,传入参数并用JDBC获得返回结果. 集算器与Java应用程序的集成结构如下: 下面举例说

java filechannel大文件的读写

java读取大文件 超大文件的几种方法 转自:http://wgslucky.blog.163.com/blog/static/97562532201332324639689/ java 读取一个巨大的文本文件既能保证内存不溢出又能保证性能 2010-09-25 11:18:50|  分类: 默认分类 |字号 订阅 import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.

java实现大文件下载(http方式)

java实现大文件下载,基于http方式,控件神马的就不说了. 思路:下载文件无非要读取文件然后写文件,主要这两个步骤,主要难点: 1.读文件,就是硬盘到内存的过程,由于jdk内存限制,不能读的太大. 2.写文件,就是响应到浏览器端的过程,http协议是短链接,如果写文件太慢,时间过久,会造成浏览器死掉. 知识点: 1.org.apache.http.impl.client.CloseableHttpClient  模拟httpClient客户端发送http请求,可以控制到请求文件的字节位置.

java+web+大文件上传下载

文件上传是最古老的互联网操作之一,20多年来几乎没有怎么变化,还是操作麻烦.缺乏交互.用户体验差. 一.前端代码 英国程序员Remy Sharp总结了这些新的接口 ,本文在他的基础之上,讨论在前端采用HTML5的API,对文件上传进行渐进式增强:     * iframe上传  * ajax上传  * 进度条  * 文件预览  * 拖放上传 1.1 传统形式 文件上传的传统形式,是使用表单元素file,参考 http://www.ruanyifeng.com/blog/2012/08/file_