Java———較大二進位文件的讀、寫

来源:http://www.cnblogs.com/ForRickHuan/archive/2017/02/20/6421796.html
-Advertisement-
Play Games

由於項目需要,需要對二進位文件進行讀寫、轉換。 文件說明:由其他程式得到的二進位文件,文件內容為:包含23543個三角形、13270個頂點的三角網所對應的721組流速矢量(u、v)文件,通俗些說,一條數據包含兩個雙精度型的數值,每組數組包含23543條數據,如果以一個雙精度數值為單位,則總共有235 ...


  由於項目需要,需要對二進位文件進行讀寫、轉換。

  文件說明:由其他程式得到的二進位文件,文件內容為:包含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程式作者的初衷應該是覺得二進位存儲比十進位節省空間吧,事實上也確實節省了一半多的空間。

  恩,此次記錄完畢。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 數據驗證控制項 --之心 在ASP中進行表單數據驗證時,通常開發者必須自己編寫一套驗證的規則,然後自己將這些代碼拷貝到ASP代碼中對錶單進行驗證。這樣進行驗證的方式實在不太方便,幸運的是,ASP.NET解決了這個問題,這就是數據驗證Web控制項。 數據驗證控制項是ASP.NET中專門用來驗證表單用戶輸入的 ...
  • 20170220問題解析請點擊今日問題下方的“【Java每日一題】20170221”查看(問題解析在公眾號首發,公眾號ID:weknow619) 今日問題: 請問該程式運行結果是什麼?(點擊以下“【Java每日一題】20170221”查看20170220問題解析) 題目原發佈於公眾號、簡書:【Jav ...
  • 1. 一個錯誤釋放記憶體的例子 下麵的場景會有什麼錯? 一切看上去都是有序的。new匹配了一個delete。但有一些地方確實是錯了。程式的行為是未定義的。至少來說,stringArray指向的100個string對象中的99個看上去都不能被正確釋放,因為他們的析構函數可能永遠不會被調用。 2. 使用n ...
  • 本節和下節介紹線程的基本協作機制wait/notify,本節介紹協作的場景,wait/notify的基本用法和原理,以及如何實現生產者/消費者模式 ... ...
  • 轉載請標明出處: "http://www.cnblogs.com/why168888/p/6422270.html" 本文出自: "【Edwin博客園】" Python文件基礎操作(入門1) 1. python文件操作之文件打開方式 | mode | 說明 | 註意 | | | | | | 'r' ...
  • 上篇文章分享了在項目實戰中自定義Mybatis的TypeHandler來處理枚舉類型。文章結尾也指出了美中不足之處,那就是每次都需要指定我們自定義的枚舉TypeHandler。 隨著項目枚舉類型的增多,每次都要寫一遍這個會令人很反感。那麼,本次我們就來解決這一痛點。 思路分析 1. 上篇文章講到, ...
  • 註:本系列博客所使用的編程語言為Java,內容主要來自於慕課網課程:初識Java微信公眾號開發(課程鏈接:http://www.imooc.com/learn/368)的學習收穫和總結。 因為微信的大規模普及性,微信公眾號開發可以開發出跨平臺使用的功能,並且使用起來簡單方便。個人使用Java作為工作 ...
  • Python第三章__函數式編程、遞歸、閉包 歡迎加入Linux_Python學習群 群號:478616847 目錄: 函數式編程 傳參與返回值 遞歸 匿名函數 閉包 高階函數 內置函數 函數式編程 傳參與返回值 遞歸 匿名函數 高階函數 內置函數 在第三章,我們引入新的概念函數,在以往的代碼編寫中 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...