java写一个文件归档的算法
来源:互联网 发布:oppo 软件商店 编辑:程序博客网 时间:2024/06/06 20:59
文件归档就是将多个小文件归档形成一个大的文件,然后在进行解归档的算法进行还原。
直接看源代码:
核心归档文件类:
package com.wang.archiver;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.util.ArrayList;import java.util.List;import org.apache.log4j.Logger;/**这里是具体算法: * 将一个文件夹下的所有文件归档成为一个文件 如果用户有多个文件,可以将其放在一个文夹下,进行归档 格式如下: 前4字节,为该文件夹名长度 * 接下来的若干字节为文件夹名 然后4个字节为该文件夹下文件个数(不包括文件夹) 接着的四个字节为第一个文件名的长度, 接下来若干字节为文件名 * 接着四个字节为文件长度,因此这个只能归档不超过4G(2的32次方)的单个文件 然后是文件夹的个数 接着的四个字节为第一个文件夹名的长度, * 接下来若干字节为文件夹名 接着四个字节为文件夹下文件个数,从而形成递归 * * @author root * */public class Archiver { private static final Logger LOG = Logger.getLogger(Archiver.class); /** * 默认的缓冲区大小 */ private static final int DEFALUT_SIZE = 10 * 1024; /** * 归档文件后缀 */ private static final String POSTFIX = ".yar"; /** * 文件夹分隔符 */ private static final String separator = "/"; /** * 文件输出流 */ private BufferedOutputStream out; /** * 归档文件输入流 */ private BufferedInputStream in; /** * 根据文件夹的前缀获取归档文件的路径 * * @param srcPath * 目标文件绝对路径 */ public void createNewArchiver(String srcPath) { String destPath = Utils.getPrefix(srcPath); createNewArchiver(srcPath, destPath); } /** * 创建归档文件 * * @param srcPath * 目标文件绝对路径 * @param destPath * 归档文件存放目录 */ public void createNewArchiver(String srcPath, String destPath) { File src = new File(srcPath); if (!destPath.contains(POSTFIX)) { String name = src.getName(); destPath = destPath + separator + name + POSTFIX; } try { out = new BufferedOutputStream(new FileOutputStream(destPath)); } catch (FileNotFoundException e) { LOG.error("destPath is exists! ", e); } setFileNameHead(src); if (!src.exists()) { LOG.warn("this file isn't exists!"); } else if (src.isDirectory()) { handleDir(src); } else if (src.isFile()) { LOG.warn("file don't need archiver!"); } // 归档完成,关闭输出流 Utils.close(out); } /** * 设置单个文件的文件头 * * @param src * 文件 */ private void setFileNameHead(File src) { String fileName = src.getName(); byte[] nameBytes = fileName.getBytes(); byte[] lens = Utils.intToBytes(nameBytes.length); Utils.write(out, lens, nameBytes); } /** * 处理归档文件夹 * * @param src */ private void handleDir(File src) { List<File> files = new ArrayList<>(); List<File> dirs = new ArrayList<>(); for (File file : src.listFiles()) { if (file.isDirectory()) { dirs.add(file); } else if (file.isFile()) { files.add(file); } } handlerFiles(files); handlerDirs(dirs); } /** * 处理各个文件夹 * * @param dirs * 文件夹 */ private void handlerDirs(List<File> dirs) { setContentHead(dirs.size()); for (File dir : dirs) { setFileNameHead(dir); handleDir(dir); } } /** * 处理各个文件 * * @param files * 文件 */ private void handlerFiles(List<File> files) { setContentHead(files.size()); for (File file : files) { writeOneFile(file); } } /** * 写出单个文件 * * @param file * 文件 */ private void writeOneFile(File file) { setFileOneHead(file); BufferedInputStream in = null; try { in = new BufferedInputStream(new FileInputStream(file)); byte[] buf = new byte[DEFALUT_SIZE]; int len = -1; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } out.flush(); } catch (IOException e) { LOG.error("read file error", e); } finally { Utils.close(in); } } /** * 设置单个文件的文件头 * * @param file */ private void setFileOneHead(File file) { setFileNameHead(file); // 文件内容最大为Integer.MAX_VALUE setContentHead((int) file.length()); } /** * 设置文件的头 * * @param size */ private void setContentHead(int size) { byte[] fileNums = Utils.intToBytes(size); Utils.write(out, fileNums); } /** * 判断传入的文件是否存在 * * @param src * @return */ private boolean isExists(File src) { if (!src.exists()) { LOG.warn("file isn't exists"); return false; } else { return true; } } public void unArchiver(String srcPath) { File src = new File(srcPath); String destPath = src.getParent(); unArchiver(src, destPath); } public void unArchiver(String srcPath, String destPath) { unArchiver(new File(srcPath), destPath); } /** * 解归档文件 * * @param src * @param destPath */ public void unArchiver(File src, String destPath) { if (!isExists(src)) { return; } /*String fullPath = destPath; String fileName = Utils.getPrefix(src.getName()); if(!destPath.endsWith(fileName)){ fullPath += separator + fileName; }*/ File dest = new File(destPath); dest.mkdirs(); try { in = new BufferedInputStream(new FileInputStream(src)); String dirName = readName(); splitDir(destPath + separator + dirName); } catch (IOException e) { LOG.error("file not found !", e); } finally { // 解归档完成,关闭输入流 Utils.close(in); } } /** * 获取一个归档文件的绝对路径 * * @param dirPath */ private void splitDir(String dirPath) { new File(dirPath).mkdirs(); int filelen = Utils.read(in); for (int i = 0; i < filelen; i++) { String fileName = readName(); splitFile(dirPath + separator + fileName); } int dirlen = Utils.read(in); for (int i = 0; i < dirlen; i++) { String dirName = readName(); splitDir(dirPath + separator + dirName); } } /** * 解压一个归档文件 * * @param dest */ private void splitFile(String dest) { BufferedOutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(dest)); int len = Utils.read(in); int bufsize = 0; int count = 1; if (len < DEFALUT_SIZE) { bufsize = len; } else { count = len / DEFALUT_SIZE + 1; bufsize = DEFALUT_SIZE; } byte[] buf = new byte[bufsize]; while (count > 0) { // 如果是最后一个改变缓冲区大小 if (count == 1) { bufsize = len % DEFALUT_SIZE; buf = new byte[bufsize]; } in.read(buf); out.write(buf); count--; } out.flush(); } catch (Exception e) { LOG.error(e); } finally { Utils.close(out); } } /** * 从输出流中读取字符串 * * @return */ private String readName() { int len = Utils.read(in); byte[] buf = new byte[len]; try { in.read(buf); } catch (IOException e) { LOG.error("file not found !", e); } return new String(buf, 0, len); }}
工具类:
package com.wang.archiver;import java.io.Closeable;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import org.apache.log4j.Logger;/** * @author root 归档类使用的工具类 */public class Utils { private static final Logger LOG = Logger.getLogger(Utils.class); /** * 关闭流 * * @param io */ public static void close(Closeable... io) { for (Closeable temp : io) { try { if (temp != null) { temp.close(); } } catch (IOException e) { e.printStackTrace(); } } } public static byte[] shortToBytes(short s) { byte[] bytes = new byte[2]; bytes[0] = (byte) (s); bytes[1] = (byte) (s >> 8); return bytes; } public static short bytesToShort(byte[] bytes) { int s0 = bytes[0] & 0xFF; int s1 = (bytes[1] & 0xFF) << 8; return (short) (s0 + s1); } /** * 将一个字节数组转为int * * @param bytes * @return */ public static int bytesToInt(byte[] bytes) { int i0 = bytes[0] & 0xFF; int i1 = (bytes[1] & 0xFF) << 8; int i2 = (bytes[2] & 0xFF) << 16; int i3 = (bytes[3] & 0xFF) << 24; return i0 + i1 + i2 + i3; } /** * 将一个int转为字节数组 * * @param i * @return */ public static byte[] intToBytes(int i) { byte[] bytes = new byte[4]; bytes[0] = (byte) i; bytes[1] = (byte) (i >> 8); bytes[2] = (byte) (i >> 16); bytes[3] = (byte) (i >> 24); return bytes; } /** * 获取文件路径的前缀 * * @param filePath * @return */ public static String getPrefix(String filePath) { int index = filePath.lastIndexOf('.'); return filePath.substring(0, index); } /** * 向一个输出流中写出byte[] * * @param out * @param data */ public static void write(OutputStream out, byte[]... data) { try { for (byte[] bs : data) { out.write(bs); } } catch (IOException e) { LOG.error("output stream write error ! ", e); } } /** * 从一个输入流中读取一个int数字 * * @param in * @return */ public static int read(InputStream in) { byte[] buf = new byte[4]; try { in.read(buf); } catch (IOException e) { LOG.error("input stream read error ! ", e); } return bytesToInt(buf); }}
测试类:
package com.wang.archiver;public class App { public static void main(String[] args) { Archiver archiver = new Archiver(); if(args.length != 2){ new Exception("参数长度是2,第一个参数是归档文件夹,第二个是归档文件夹存放目录!"); return; } archiver.createNewArchiver(args[0],args[1]); }}
测试类2:
package com.wang.archiver;public class App2 { public static void main(String[] args) { Archiver archiver = new Archiver(); if(args.length != 2){ new Exception("参数长度是2,第一个参数是归档文件,第二个是解归档文件夹存放目录!"); return; } archiver.unArchiver(args[0],args[1]); }}
阅读全文
0 0
- java写一个文件归档的算法
- 用java写的一个排序算法
- 一个java写的文件查看程序
- 一个写文件的java类
- 关于用JAVA写菱形的一个对称算法
- 一个java写的贪心算法实现删数问题
- java写的一个用字节流复制文件的方法
- 教你写一个可以运行java的bat文件
- 用JAVA打开一个已经写好的TXT文件
- 怎样用java写一个简单的文件复制程序
- 文件的归档压缩
- java解归档tar文件
- 学长写的一个处理大数据多个文件的排序算法
- 一个清理归档的脚本!
- Java 写的一个单链表
- java写的MD5算法
- JAVA写的冒泡算法
- java写的常见算法
- 2986:拼点游戏( 4.6算法之贪心)
- activit配置json文件进行后台开发
- eclipse-2017修复 jsp中在option里面写<c:if></c:if>代码报错解决
- [日推荐]『共享记账』你的私人会计师!
- IDEA tomcat部署报错
- java写一个文件归档的算法
- 联想 U盘 写保护
- 在windows中安装RabbitMQ扩展
- Cg Programming/Unity/Cutaways
- ios最简洁二维码扫描以及跳转
- Android常用Dialog对话框大全
- PAT 1112. Stucked Keyboard (20) 随后再看
- /bin/bash^M: bad interpreter: 没有那个文件或目录
- java引用对象和创建对象过程分析