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

在Java中使用byte[]数组将.gz文件拆分为指定的文件大小,java,split,gzip,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.D

我编写了一段代码,使用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);

}
  }
package com.bitsightech.collection.packaging;
导入java.io.BufferedInputStream;
导入java.io.BufferedOutputStream;
导入java.io.DataInputStream;
导入java.io.DataOutputStream;
导入java.io.File;
导入java.io.FileInputStream;
导入java.io.FileOutputStream;
导入java.util.regex.Matcher;
导入java.util.regex.Pattern;
导入org.apache.log4j.Logger;
公共类FileSplitterBytewise
{
私有静态记录器=Logger.getLogger(filespliterByteWise.class);
私有静态最终长KB=1024;
私有静态最终长MB=KB*KB;
私有文件输入流fis;
私有文件输出流;
私有数据输入流dis;
私有数据输出流dos;
公共布尔拆分(文件输入文件、字符串拆分大小)
{  
int expectedNoOfFiles=0;
尝试
{  
double parentFileSizeInB=inputFile.length();
Pattern p=Pattern.compile(“(\\d+)\\s([MmGgKk][Bb]);
匹配器m=p.匹配器(拆分大小);
m、 匹配();
字符串FileSizeString=m.group(1);
串单位=m组(2);
double FileSizeInMB=0;
试一试{
if(unit.toLowerCase().equals(“kb”))
FileSizeInMB=Double.parseDouble(FileSizeString)/KB;
else if(unit.toLowerCase()等于(“mb”))
FileSizeInMB=Double.parseDouble(FileSizeString);
else if(unit.toLowerCase()等于(“gb”))
FileSizeInMB=Double.parseDouble(FileSizeString)*KB;
}捕获(数字格式){
logger.error(“预期文件大小的无效数字[“+FileSizeInMB+””);
}
double fileSize=FileSizeInMB*MB;
int fileSizeInByte=(int)Math.ceil(fileSize);
double noOFFiles=parentFileSizeInB/fileSizeInByte;
expectedNoOfFiles=(int)Math.ceil(noOFFiles);
int splinterCount=1;
fis=新文件InputStream(inputFile);
dis=新的数据输入流(新的BufferedInputStream(fis));
fos=新的文件输出流(“F:\\ff\\\”+“\u部分\u”+splinterCount+“\u部分\u”+预期的NoOffiles);
dos=新的数据输出流(新的缓冲输出流(fos));
字节[]数据=新字节[(int)fileSizeInByte];

while(splinterCount我建议创建更多的方法。在
split()
中,代码中有一个复杂的字符串处理部分;最好创建一个方法,将人性化字符串作为输入并返回您要查找的数字。(这也会使您更容易测试例程的这一部分;您现在无法进行测试。)

一旦它被拆分,并且您正在编写测试用例,您可能会发现,如果字符串不包含
kb
mb
gb
,则生成的错误消息非常令人困惑——它将错误归咎于数字
0
,而不是指出字符串没有预期的单位

使用
int
存储文件大小意味着您的程序将永远不会处理文件。您应该坚持使用
long
double
double
对于实际限制为整数值的内容感觉不正确,但我无法快速思考它为什么会失败。)

像这样分配几GB的内存会破坏您的性能--这可能是一个巨大的内存分配(可能会被认为是在对手的控制下分配的内存;这取决于您的安全模型,这可能是一个大问题,也可能不是一个大问题)

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

        fos = new FileOutputStream("F:\\ff\\" + "_part_" + splinterCount + "_of_" + expectedNoOfFiles);
您似乎只打开过一个文件输出流。您的帖子可能应该说“只有第一个有效”,因为您似乎还没有在创建三个或更多片段的文件上尝试过

catch(Exception e)
此时,您已经能够发现程序中的错误;您可以选择完全忽略这些错误。当然,您可以记录错误消息,但实际上无法使用您记录的数据调试您的程序。您应该至少记录异常类型、消息,甚至完整的堆栈跟踪。这种数据组合非常有用当你试图解决问题时,尤其是在几个月的时间里,你已经忘记了它是如何工作的

你能帮我修一下这个吗

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);

}
  }
我会使用

  • 删除数据输入/输出流,您不需要它们
  • 使用in.read(数据)来读取整个块,而不是一次读取一个字节。一次读取一个字节要慢得多
  • 或者读取整个数据数组,您读取的数据就少了一个
  • 当到达文件末尾时停止,它可能不是文件大小的整数倍
  • 只写你读过的数据块,如果你的数据块有1MB字节,剩下100KB,你应该只在最后读写100KB
  • 完成后关闭文件(尤指有缓冲流时)
  • 您“拆分”将所有内容写入同一个文件(因此它实际上不会拆分),您需要在循环中创建、写入和关闭输出文件
  • 当您可以/应该使用局部变量时,不要使用字段
  • 将使用长度作为长字节
  • 该模式忽略不正确的输入和输出