java语言实现文档的归档解归档

首先设计归档的协议

文件归档与解归档
运用IO流技术,把若干文件以流的方式写到一个文件里去,但是要区分文件和文件之间的边界,就需要设计每个文件的“头”。文件在磁盘上以字节数组的方式存在。“头”包含文件的扩展名类型(1个字节),文件的长度(4个字节),文件内容。解归档:先读文件类型,再读文件长度,接着读文件长度个字节。
增强版:文件名长度(1个字节长度),文件名字节数组(字符串解码getBytes),文件长度(4个字节),文件内容。

代码实现归档与解档:

//Archiver.java

  1 import java.io.FileInputStream;
  2 import java.io.FileOutputStream;
  3 import java.io.IOException;
  4 
  5 public class Archiver {
  6     public void newArchiverFile(String[] srcPaths, String yarPath) {
  7         FileOutputStream fout = null;
  8         try {
  9             //创建yar归档文件的输出流
 10             fout = new FileOutputStream(yarPath);
 11             for(String srcPath : srcPaths) {
 12                 addFile(srcPath, fout);
 13                 
 14             }
 15         } catch (Exception e) {
 16             e.printStackTrace();
 17         } finally {
 18             if (fout != null) {
 19                 try {
 20                     fout.close();
 21                 } catch (IOException e) {
 22                     e.printStackTrace();
 23                 }
 24             }
 25         }
 26     }
 27 
 28     /**
 29      * 向yar归档文件中添加文件
 30      * @param srcPath
 31      * @param fout
 32      */
 33     private void addFile(String srcPath, FileOutputStream fout) {
 34         FileInputStream fin = null;
 35         try {
 36             //1. 取出文件类型
 37             int fType = getFileType(srcPath);
 38             
 39             //2. 取出文件的长度
 40             fin = new FileInputStream(srcPath);
 41             int length = fin.available();
 42             
 43             //3. 将类型写入fout
 44             byte bFType = (byte) fType;
 45             fout.write(new byte[] {bFType});
 46             
 47             //4. 将长度写入yar中
 48             byte[] bytes = Int2ByteArr(length);
 49             fout.write(bytes);
 50             
 51             //5. 写入文件内容
 52             int len = -1;
 53             byte[] buffer = new byte[1024];
 54             while((len = fin.read(buffer)) != -1) {
 55                 fout.write(buffer, 0, len);
 56             }
 57             
 58         } catch (Exception e) {
 59             
 60             e.printStackTrace();
 61         } finally {
 62             if (fin != null) {
 63                 try {
 64                     fin.close();
 65                 } catch (IOException e) {
 66                     e.printStackTrace();
 67                 }
 68             }
 69         }
 70         
 71     }
 72 
 73     private byte[] Int2ByteArr(int i) {
 74         byte[] bytes = new byte[4];
 75         bytes[0] = (byte) i;
 76         bytes[1] = (byte) (i >> 8);
 77         bytes[2] = (byte) (i >> 16);
 78         bytes[3] = (byte) (i >> 24);
 79         return bytes;
 80     }
 81 
 82     /**
 83      * 得到文件类型
 84      * 0-txt
 85      * 1-jpg
 86      * 2-avi
 87      * 3-gif
 88      * 4-exe
 89      * 5-mp4
 90      * @param srcPath
 91      * @return
 92      */
 93     private int getFileType(String srcPath) {
 94         String ext = srcPath.substring(srcPath.lastIndexOf(".")).toLowerCase();
 95         int type = -1;
 96         if (".txt".equals(ext)) {
 97             type = 0;
 98         } else if (".jpg".equals(ext)) {
 99             type = 1;
100         } else if (".avi".equals(ext)) {
101             type = 2;
102         } else if (".gif".equals(ext)) {
103             type = 3;
104         } else if (".exe".equals(ext)) {
105             type = 4;
106         } else if (".mp4".equals(ext)) {
107             type = 5;
108         } else {
109             type = -1;
110         }
111         
112         return type;
113     }
114     
115     /**
116      * 向原有yar中添加新文件
117      */
118     public void addFile(String srcPath, String yarPath) {
119         try {
120             FileOutputStream fos = new FileOutputStream(yarPath,true);//追加
121             addFile(srcPath, fos);
122             fos.close();
123         } catch (Exception e) {
124             e.printStackTrace();
125         }
126     }
127     
128     /**
129      * 解档文件
130      */
131     public void unarchive(String yarPath, String destDir) {
132         try {
133             FileInputStream fis = new FileInputStream(yarPath);
134             int i = 1;
135             //循环读取下一个文件
136             while (readNextFile(destDir, (i++) + "", fis)) {
137                 
138             }
139             fis.close();    
140         } catch (Exception e) {
141             e.printStackTrace();
142         }
143         
144     }
145 
146     private boolean readNextFile(String destDir,String name, FileInputStream fis) {
147         try {
148             //文件类型
149             int type = fis.read();
150             //文件的扩展名
151             String ext = getFileExt(type);
152             if (type == -1) {
153                 return false;
154             }
155             
156             //构造文件
157             FileOutputStream fout = new FileOutputStream(destDir + "/" + name + ext);
158             
159             // 1.读取文件长度
160             byte[] bytes = new byte[4];
161             fis.read(bytes);
162             
163             // 2.转换字节数组为int
164             int fileLength = byteArr2Int(bytes);
165             
166             // 3.读取文件
167             byte[] buffer = new byte[1024];
168 
169             // 计算读取文件的循环次数
170             int count = 0;
171             if (fileLength / buffer.length == 0) {
172                 count = fileLength / buffer.length;
173             }
174             else {
175                 count = fileLength / buffer.length + 1;
176             }
177             //开始循环读取
178             for (int i = 0; i < count; i++) {
179                 if (i != (count - 1)) {
180                     fis.read(buffer);
181                     fout.write(buffer);
182                 }
183                 else {
184                     byte[] buf0 = new byte[fileLength - ((count - 1) * buffer.length)];
185                     fis.read(buf0);
186                     fout.write(buf0);
187                 }
188             }
189             fout.close();
190             return true;
191         } catch (Exception e) {
192             e.printStackTrace();
193         }
194         
195         return false;
196     }
197 
198     private String getFileExt(int type) {
199         String ext = ".tmp";
200         switch (type) {
201         case 0:
202             ext = ".txt";
203             break;
204         case 1:
205             ext = ".jpg";
206             break;
207         case 2:
208             ext = ".avi";
209             break;
210         case 3:
211             ext = ".gif";
212             break;
213         case 4:
214             ext = ".exe";
215             break;
216         case 5:
217             ext = ".mp4";
218             break;
219         default:
220             ext = ".tmp";
221             break;
222         }
223         return ext;
224     }
225 
226     /**
227      * 将长度为4的字节数组转换成int
228      * @param bytes
229      * @return
230      */
231     private int byteArr2Int(byte[] bytes) {
232         //int i = (int)(bytes[3] << 24 | bytes[2] << 16 | bytes[1] << 8 | bytes[0]);
233         int i0 = (bytes[3] & 0xff) << 24;
234         int i1 = (bytes[2] & 0xff) << 16;
235         int i2 = (bytes[1] & 0xff) << 8;
236         int i3 = (bytes[0] & 0xff);
237         return i0 | i1 | i2 | i3;
238     }
239 }

测试代码:

//App.java

 1 import org.junit.Test;
 2 
 3 public class App {
 4 
 5     /**
 6      * 新建归档文件
 7      */
 8     @Test
 9     public void newArchiveFile() {
10         Archiver archiver = new Archiver();
11         String[] srcPaths = { "D:/arch/Sax.JPG", "D:/arch/1.mp4", "D:/arch/java笔记.txt"};
12         String yarPath = "d:/arch/myYar.yar";
13         archiver.newArchiverFile(srcPaths, yarPath);
14         System.out.println("over");
15     }
16     
17     /**
18      * 向原有归档文件中添加新文件
19      */
20     @Test
21     public void addFile(){
22         Archiver archiver = new Archiver();
23         archiver.addFile("D:/arch/hello.txt", "d:/arch/myYar.yar");
24     }
25     
26     /**
27      * 解档文件
28      */
29     @Test
30     public void unarchiveFile() {
31         Archiver archiver = new Archiver();
32         archiver.unarchive("d:/arch/myYar.yar", "d:/arch/unarch");
33     }
34 
35 }

newArchiveFile()在D:arch目录下生成了myYar.yar归档文件大小为1.MP4 java笔记.txt Sax.jpg三个文件之和加15字节

unarchiveFile()之后在d:/arch/unarch下还原文件

原文地址:https://www.cnblogs.com/8386blogs/p/7510074.html