使用byte []数组将.gz文件拆分为Java中的指定文件大小

时间:2012-03-14 09:20:12

标签: java split gzip

我编写了一个代码,使用byte []数组将.gz文件拆分为用户指定的部分。但for循环不是读/写父文件的最后一部分,而是小于数组大小。你可以帮我解决这个问题吗?

package com.bitsighttech.collection.packaging;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;

public class FileSplitterBytewise
{
private static Logger logger = Logger.getLogger(FileSplitterBytewise.class);
private static final long KB = 1024;
private static final long MB = KB * KB;

private FileInputStream fis;
private FileOutputStream fos;   
private DataInputStream dis;
private DataOutputStream dos;

public boolean split(File inputFile, String splitSize)  
{  

    int expectedNoOfFiles =0;       

    try  
    {  
        double parentFileSizeInB = inputFile.length();

        Pattern p = Pattern.compile("(\\d+)\\s([MmGgKk][Bb])");
        Matcher m = p.matcher(splitSize);
        m.matches();

        String FileSizeString = m.group(1);
        String unit = m.group(2);
        double FileSizeInMB = 0;

        try {
            if (unit.toLowerCase().equals("kb"))
                FileSizeInMB = Double.parseDouble(FileSizeString) / KB;         
            else if (unit.toLowerCase().equals("mb"))
                FileSizeInMB = Double.parseDouble(FileSizeString);          
            else if (unit.toLowerCase().equals("gb"))
                FileSizeInMB = Double.parseDouble(FileSizeString) * KB;         
        } catch (NumberFormatException e) {
            logger.error("invalid number [" + FileSizeInMB  + "] for expected file size");
        }

        double fileSize = FileSizeInMB * MB;
        int fileSizeInByte = (int) Math.ceil(fileSize);
        double noOFFiles = parentFileSizeInB/fileSizeInByte;            
        expectedNoOfFiles =  (int) Math.ceil(noOFFiles);                    
        int splinterCount = 1;
        fis = new FileInputStream(inputFile);
        dis = new DataInputStream(new BufferedInputStream(fis));
        fos = new FileOutputStream("F:\\ff\\" + "_part_" + splinterCount + "_of_" + expectedNoOfFiles);
        dos = new DataOutputStream(new BufferedOutputStream(fos));  

        byte[] data = new byte[(int) fileSizeInByte];

        while ( splinterCount <= expectedNoOfFiles ) {                  

            int i;          
            for(i = 0; i<data.length-1; i++)
            {
                data[i] = s.readByte();             
            }               
            dos.write(data);
            splinterCount ++; 
            }
    }       
    catch(Exception e)  
    {  
        logger.error("Unable to split the file " + inputFile.getName() + " in to " + expectedNoOfFiles);
        return false;
    }  


    logger.debug("Successfully split the file [" + inputFile.getName() + "] in to " + expectedNoOfFiles + " files");
    return true;
}    

public static void main(String args[]) 
{
    String FilePath1 = "F:\\az.gz";     
    File  file= new File(FilePath1);
    FileSplitterBytewise fileSplitter = new FileSplitterBytewise();
    String splitlen = "1 MB";

    fileSplitter.split(file, splitlen);

}
  }

2 个答案:

答案 0 :(得分:0)

我建议制作更多方法。你在split()中有一个复杂的字符串处理代码段;最好制作一个方法,将人性化的字符串作为输入,并返回您正在寻找的数字。 (这也会让你更容易测试这部分例程;你现在无法测试它。)

一旦拆分并且您正在编写测试用例,如果字符串不包含kbmb或{{1>,您可能会发现生成的错误消息非常令人困惑 - 它为错误指责数字gb,而不是指出字符串没有预期的单位。

使用0存储文件大小意味着您的程序永远不会处理文件larger than two gigabytes。你应该坚持使用intlong。 (double对于实际上限于整数值的内容感觉不对,但我无法快速思考为什么失败。)

double

分配这样几千兆字节会破坏你的性能 - 这是一个潜在的巨大的内存分配(可能被认为是在对手的控制之下;根据你的安全模型,这可能会或者可能不是什么大不了的事)。不要试图将整个文件整合在一起。

您似乎一次只读取和写入一个字节的文件。这是非常慢的性能的保证。今天早些时候对另一个问题进行了一些性能测试,我发现我的机器可以读取(从热缓存)使用131kb块比两个字节块快2000倍。单字节块会更糟糕。对于如此小的尺寸,冷缓存会更糟糕。

byte[] data = new byte[(int) fileSizeInByte];

您似乎只打开一个文件输出流。您的帖子可能应该说“只有第一部作品”,因为看起来您还没有在创建三件或更多件的文件上尝试过它。

        fos = new FileOutputStream("F:\\ff\\" + "_part_" + splinterCount + "_of_" + expectedNoOfFiles);

此时,您已经能够在程序中发现错误;你选择完全忽略它们。当然,您记录了一条错误消息,但实际上您无法使用您记录的数据调试程序。您应该至少记录异常类型,消息,甚至可能是完整的堆栈跟踪。在尝试解决问题时,这种数据组合非常有用,特别是在您忘记其工作原理的几个月内。

答案 1 :(得分:0)

  

你可以帮我解决这个问题吗?

我会用;

  • 删除DataInput / OutputStreams,您不需要它们。
  • 使用in.read(data)来读取整个块,而不是一次读取一个字节。一次读一个字节要慢得多!
  • 或者读取整个数据数组,你正在阅读一个。
  • 当你到达文件末尾时停止,它可能不是大小的整数倍。
  • 只写你读过的内容,如果1 MB字节的块还有100 KB,那么你最后只能读/写100 KB。
  • 完成后关闭文件,特别是因为你有一个缓冲流。
  • 你“拆分”将所有内容写入同一个文件(因此它实际上并不拆分)你需要在循环中创建,写入和关闭输出文件。
  • 当您/应该使用局部变量时,不要使用字段。
  • 将长度用作长字节。
  • 模式忽略不正确的输入,并且您的模式与您检查的测试不匹配。例如您的模式允许1 G1 k,但这些将被视为1 MB。