大数据开发之文件归档和解归档
一,归档
在大数据开发中往往要运算海量数据,可是这些数据分布在许多小文件中,传输和运算十分不方便,为此我们得进行文件归档
即把几个小文件写到一个文件中形成大文件,可是我们要怎么写呢?每个团队有每个团队的方法,下面介绍我自己的方法。
格式: 4个字节 文件名称的数据存储大小(n,表示存储的文件有几个字节)
n个字节 文件名称
4个字节 文件内容的数据存储大小(m,表示存储的文件有几个字节)
m个字节 文件内容
有几个小文件,那么归档后的文件就有多少个这样的格式。
第一步 定义一个函数,使用4个字节,存储 文件名称的数据存储大小,归档的时候使用,看代码
public byte[] int2Bytes(int i) { byte[] arr = new byte[4]; arr[0]=(byte)i; arr[1]=(byte)(i>>8); arr[1]=(byte)(i>>8); arr[1]=(byte)(i>>8); return arr; }
第2步定义一个函数,把这4个字节的二进制数据转换成我们能看懂的数据,解归档的时候用
public int Bytes2int(byte bytes[]) { int i0=bytes[0] & 0xFF; //byte类型运算时会自动转成int类型,为了防止字节数据的第一位为1而导致扩充后前面全补1导致正数变负数 int i1 = (bytes[1] & 0xFF) << 8 ; int i2 = (bytes[2] & 0xFF) << 16 ; int i3 = (bytes[3] & 0xFF) << 24 ; return i0 | i1 | i2 | i3 ; }
归档代码如下
package 归档; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class Archivee { public static void main(String[] args) throws Exception { FileOutputStream fos = new FileOutputStream("d:/arch/x.xar"); fos.write(addFile("D:/arch/a.xls")); fos.write(addFile("D:/arch/b.xml")); fos.write(addFile("D:/arch/c.txt")); fos.close(); } public static byte[] addFile(String path) throws Exception { //文件路径 File f = new File(path); //文件名 String fname = f.getName(); //文件名数组 byte[] fnameBytes = fname.getBytes(); //文件内容长度 int len = (int) f.length(); //计算总长度 int total = 4 + fnameBytes.length + 4 + len; byte[] bytes = new byte[total]; //1. 写入文件名长度 byte[] fnameLenArr = Util.int2Bytes(fnameBytes.length); System.arraycopy(fnameLenArr, 0, bytes, 0, 4); //2. 写入文件名本身 System.arraycopy(fnameBytes, 0, bytes, 4, fnameBytes.length); //3. 写入文件内容长度 byte[] fcontentLenArr = Util.int2Bytes(len); System.arraycopy(fcontentLenArr, 0, bytes, 4 + fnameBytes.length, 4); //4. 写入文件内容 //读取文件内容到数组中 ByteArrayOutputStream baos = new ByteArrayOutputStream(); FileInputStream fis = new FileInputStream(f); byte[] buf = new byte[1024]; int len0 = 0; while(((len0 = fis.read(buf)) != -1)){ baos.write(buf, 0, len0); } fis.close(); //得到文件内容 byte[] fcontentArr = baos.toByteArray(); System.arraycopy(fcontentArr, 0, bytes, 4 + fnameBytes.length + 4 , fcontentArr.length); return bytes; } }
三,解归档
首先要定义一个实体类来存储文件名称和文件内容,然后放到List集合中,然后同一写出去。
package 归档; class FileBean { private String fileName; private byte[] fileContent; public FileBean() { } public FileBean(String fileName, byte[] fileContent) { this.fileName = fileName; this.fileContent = fileContent; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } public byte[] getFileContent() { return fileContent; } public void setFileContent(byte[] fileContent) { this.fileContent = fileContent; } }
具体代码:
package 归档; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; public class UnArchiver { public static void main(String[] args)throws Exception { List<FileBean> files = new ArrayList<FileBean>(); FileInputStream fis = new FileInputStream("d:/arch/x.xar"); FileBean fileBean = null; while((fileBean = readNextFile(fis))!= null) { files.add(fileBean); } fis.close(); FileOutputStream fos = null; for(FileBean fb : files) { fos = new FileOutputStream("d:/arch/unarch/"+fb.getFileName()); fos.write(fb.getFileContent()); fos.close(); } } public static FileBean readNextFile(FileInputStream fis) throws Exception { byte[] bytes4 = new byte[4]; int res = fis.read(bytes4); if(res == -1){ return null; } //文件名长度 int fnameLen = Util.Bytes2int(bytes4); //文件名数组 byte[] fileNameBytes = new byte[fnameLen]; fis.read(fileNameBytes); //得到文件名 String fname = new String(fileNameBytes); //再读取4个字节作为文件内容的长度 fis.read(bytes4); int fileContentLen = Util.Bytes2int(bytes4); //读取文件内容 byte[] fileContentBytes = new byte[fileContentLen]; fis.read(fileContentBytes); return new FileBean(fname,fileContentBytes); } }