Java實(shí)現(xiàn)較大二進(jìn)制文件的讀、寫方法
由于項目需要,需要對二進(jìn)制文件進(jìn)行讀寫、轉(zhuǎn)換。
文件說明:由其他程序得到的二進(jìn)制文件,文件內(nèi)容為:包含23543個三角形、13270個頂點(diǎn)的三角網(wǎng)所對應(yīng)的721組流速矢量(u、v)文件,通俗些說,一條數(shù)據(jù)包含兩個雙精度型的數(shù)值,每組數(shù)組包含23543條數(shù)據(jù),如果以一個雙精度數(shù)值為單位,則總共有23543 * 721 * 2 =33,949,006條數(shù)據(jù)。由Fortran程序以每 8 Byte存儲一個數(shù)值的二進(jìn)制文件存儲,最終文件大小為下圖所示:
測試:從該文件讀出數(shù)據(jù)之后,轉(zhuǎn)換為十進(jìn)制,存儲到另一個文件中。
/**
* 針對大文件存儲,請依次調(diào)用beginSave、AddSave、endSave。
*
* @author CK
*
*/
public class DataUtil {
DataOutputStream BinaryOut=null;
BufferedWriter TextOut=null;
String FilePath=null;
enum SaveFileType{Text,Binary};
SaveFileType SaveFileType;
/**
* double轉(zhuǎn)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[]轉(zhuǎn)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);
}
/**
* 大型數(shù)據(jù)存儲之開始存儲
* @param FilePath 文件路徑
* @param saveFileType 保存的文件類型,文本文件、雙精度所存的二進(jìn)制文件
* @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 若是文本存儲則無要求,若是雙精度的二進(jìn)制文件,以若干空格隔開
* @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;
}
/**
* 大型文件存儲之結(jié)束保存,清空緩存、關(guān)閉文件。
* @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
* 文件內(nèi)容
* @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;
}
/**
* 雙精度存為二進(jìn)制數(shù)據(jù)(一次存儲)
*
* @param DataStr 雙精度數(shù)據(jù)組成的字符串,以若干空格隔開
* @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));
// 數(shù)據(jù)處理
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互轉(zhuǎn)為在互聯(lián)網(wǎng)上查到的方法,具體是哪位大神的我忘記了,在這里為了記錄就貼出來啦,上述代碼包含了處理小型文件時,將所有內(nèi)容存在緩存中,之后再一次性寫入文本文件、二進(jìn)制文件中的方法,還包含了對較大型文件的讀寫方法,下面是自己的一個讀寫測試。
/**
* 測試二進(jìn)制大文件讀寫(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); //初始化,創(chuàng)建文件,采用文件追加存儲的思路
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(); //將還在緩存中的數(shù)據(jù)寫入到文件中,關(guān)閉文件。
}
}
此次測試代碼很快就run完了,但是輸出文件的生成大概用了近半分鐘(刻意秒表計時了一次),嘗試用一次性讀寫的辦法,卡很久,也沒有出結(jié)果。所得的十進(jìn)制文本文件,大小為這么多:

我想,原來Fortran程序作者的初衷應(yīng)該是覺得二進(jìn)制存儲比十進(jìn)制節(jié)省空間吧,事實(shí)上也確實(shí)節(jié)省了一半多的空間。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot基于Mybatis-Plus自動代碼生成
這篇文章主要介紹了SpringBoot基于Mybatis-Plus自動代碼生成,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
SpringBoot中通過實(shí)現(xiàn)WebMvcConfigurer參數(shù)校驗(yàn)的方法示例
這篇文章主要介紹了SpringBoot中通過實(shí)現(xiàn)WebMvcConfigurer參數(shù)校驗(yàn)的方法示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
Java中將File轉(zhuǎn)化為MultipartFile的操作
這篇文章主要介紹了Java中將File轉(zhuǎn)化為MultipartFile的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10
Arrays.sort如何實(shí)現(xiàn)降序排序
這篇文章主要介紹了Arrays.sort如何實(shí)現(xiàn)降序排序問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11
Java經(jīng)典設(shè)計模式之模板方法模式定義與用法示例
這篇文章主要介紹了Java經(jīng)典設(shè)計模式之模板方法模式,簡單說明了模板方法模式的原理、定義,并結(jié)合實(shí)例形式分析了java模板方法模式的具體使用方法,需要的朋友可以參考下2017-08-08
如何使用RequestHeaders添加自定義參數(shù)
這篇文章主要介紹了使用RequestHeaders添加自定義參數(shù)方式,具有很好的參考價值,希望對大家有所幫助。2022-02-02

