拆分并加入java中的二进制文件

时间:2010-12-13 18:04:20

标签: java file-io

我正在尝试将二进制文件(如视频/音频/图像)分成每个100kb的块,然后将这些块连接起来以取回原始文件。 我的代码似乎正在工作,在它分割文件并加入块的意义上,我得到的文件与原始文件大小相同。然而,问题是内容被截断 - 也就是说,如果它是一个视频文件,它会在2秒后停止,如果它是图像文件,那么只有上半部分看起来正确。

以下是我正在使用的代码(如果您愿意,我可以发布整个代码):

分割:

File ifile = new File(fname); 
FileInputStream fis;
String newName;
FileOutputStream chunk;
int fileSize = (int) ifile.length();
int nChunks = 0, read = 0, readLength = Chunk_Size;
byte[] byteChunk;
try {
    fis = new FileInputStream(ifile);
    StupidTest.size = (int)ifile.length();
    while (fileSize > 0) {
        if (fileSize <= Chunk_Size) {
            readLength = fileSize;
        }
        byteChunk = new byte[readLength];
        read = fis.read(byteChunk, 0, readLength);
        fileSize -= read;
        assert(read==byteChunk.length);
        nChunks++;
        newName = fname + ".part" + Integer.toString(nChunks - 1);
        chunk = new FileOutputStream(new File(newName));
        chunk.write(byteChunk);
        chunk.flush();
        chunk.close();
        byteChunk = null;
        chunk = null;
    }
    fis.close();
    fis = null;

为了加入文件,我将所有块的名称放在List中,然后按名称对其进行排序,然后运行以下代码:

File ofile = new File(fname);
FileOutputStream fos;
FileInputStream fis;
byte[] fileBytes;
int bytesRead = 0;
try {
    fos = new FileOutputStream(ofile,true);             
    for (File file : files) {
        fis = new FileInputStream(file);
        fileBytes = new byte[(int) file.length()];
        bytesRead = fis.read(fileBytes, 0,(int)  file.length());
        assert(bytesRead == fileBytes.length);
        assert(bytesRead == (int) file.length());
        fos.write(fileBytes);
        fos.flush();
        fileBytes = null;
        fis.close();
        fis = null;
    }
    fos.close();
    fos = null;

7 个答案:

答案 0 :(得分:10)

我只能在代码中发现2个潜在的错误:

int fileSize = (int) ifile.length();

当文件超过2GB时,上述操作失败,因为int无法容纳更多文件。

newName = fname + ".part" + Integer.toString(nChunks - 1);

这样构造的文件名应该以非常具体的方式排序。使用默认字符串排序时,name.part10将在name.part2之前出现。您想提供一个自定义Comparator,它将部件号提取并解析为int,然后进行比较。

答案 1 :(得分:3)

  

为了加入文件,我将所有块的名称放在List中,然后按名称对其进行排序,然后运行以下代码:

但你的名字是以下形式:

newName = fname + ".part" + Integer.toString(nChunks - 1);

仔细考虑如果您有11个或更多部件会发生什么。哪个字符串按字母顺序排在第一位:“。part10”或“.part2”? (答案:“。part10”,因为'1'在字符编码中位于'2'之前。)

答案 2 :(得分:1)

是否有超过10个块?然后程序将连接* .part1 + * .part10 + * .part2,依此类推。

答案 3 :(得分:1)

分割文件:-----&gt;

import java.io.*;

class Split
{


  public static void main(String args[])throws IOException
   {

    Console con=System.console();
    System.out.println("enter the file name");
    String path=con.readLine();
    File f= new File(path);
    int filesize=(int)f.length();
    FileInputStream fis= new FileInputStream(path); 

    int size;
    System.out.println("enter file size for split");
        size=Integer.parseInt(con.readLine());


    byte b[]=new byte[size];

    int ch,c=0;




    while(filesize>0)
           {
                 ch=fis.read(b,0,size);


        filesize = filesize-ch;


                String fname=c+"."+f.getName()+"";
        c++;
        FileOutputStream fos= new FileOutputStream(new File(fname));
        fos.write(b,0,ch);
        fos.flush();
        fos.close();

        }

fis.close();

}

}

答案 4 :(得分:1)

public class FileSplitter {
    private static final int BUFSIZE = 4*1024;
    public boolean needsSplitting(String file, int chunkSize) {
        return new File(file).length() > chunkSize;
    }
    private static boolean isASplitFileChunk(String file) {
        return chunkIndexLen(file) > 0;
    }
    private static int chunkIndexLen(String file) {
        int n = numberOfTrailingDigits(file);
        if (n > 0) {
            String zeroes = new String(new char[n]).replace("\0", "0");
            if (file.matches(".*\\.part[0-9]{"+n+"}?of[0-9]{"+n+"}?$") && !file.endsWith(zeroes) && !chunkNumberStr(file, n).equals(zeroes)) {
                return n;
            }
        }
        return 0;
    }
    private static String getWholeFileName(String chunkName) {
        int n = chunkIndexLen(chunkName);
        if (n>0) {
            return chunkName.substring(0, chunkName.length() - 7 - 2*n); // 7+2n: 1+4+n+2+n : .part012of345
        }
        return chunkName;
    }
    private static int getNumberOfChunks(String filename) {
        int n = chunkIndexLen(filename);
        if (n > 0) {
            try {
                String digits = chunksTotalStr(filename, n);
                return Integer.parseInt(digits);
            } catch (NumberFormatException x) { // should never happen
            }
        }
        return 1;
    }
    private static int getChunkNumber(String filename) {
        int n = chunkIndexLen(filename);
        if (n > 0) {
            try {
                // filename.part001of200
                String digits = chunkNumberStr(filename, n);
                return Integer.parseInt(digits)-1;
            } catch (NumberFormatException x) {
            }
        }
        return 0;
    }
    private static int numberOfTrailingDigits(String s) {
        int n=0, l=s.length()-1;
        while (l>=0 && Character.isDigit(s.charAt(l))) {
            n++; l--;
        }
        return n;
    }
    private static String chunksTotalStr(String filename, int chunkIndexLen) {
        return filename.substring(filename.length()-chunkIndexLen);
    }
    protected static String chunkNumberStr(String filename, int chunkIndexLen) {
        int p = filename.length() - 2 - 2*chunkIndexLen; // 123of456
        return filename.substring(p,p+chunkIndexLen);
    }
    // 0,8 ==> part1of8; 7,8 ==> part8of8
    private static String chunkFileName(String filename, int n, int total, int chunkIndexLength) {
        return filename+String.format(".part%0"+chunkIndexLength+"dof%0"+chunkIndexLength+"d", n+1, total);
    }
    public static String[] splitFile(String fname, long chunkSize) throws IOException {
        FileInputStream fis = null;
        ArrayList<String> res = new ArrayList<String>();
        byte[] buffer = new byte[BUFSIZE];
        try {
            long totalSize = new File(fname).length();
            int nChunks = (int) ((totalSize + chunkSize - 1) / chunkSize);
            int chunkIndexLength = String.format("%d", nChunks).length();
            fis = new FileInputStream(fname);
            long written = 0;
            for (int i=0; written<totalSize; i++) {
                String chunkFName = chunkFileName(fname, i, nChunks, chunkIndexLength);
                FileOutputStream fos = new FileOutputStream(chunkFName);
                try {
                    written += copyStream(fis, buffer, fos, chunkSize);
                } finally {
                    Closer.closeSilently(fos);
                }
                res.add(chunkFName);
            }
        } finally {
            Closer.closeSilently(fis);
        }
        return res.toArray(new String[0]);
    }
    public static boolean canJoinFile(String chunkName) {
        int n = chunkIndexLen(chunkName);
        if (n>0) {
            int nChunks = getNumberOfChunks(chunkName);
            String filename = getWholeFileName(chunkName);
            for (int i=0; i<nChunks; i++) {
                if (!new File(chunkFileName(filename, i, nChunks, n)).exists()) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }
    public static void joinChunks(String chunkName) throws IOException {
        int n = chunkIndexLen(chunkName);
        if (n>0) {
            int nChunks = getNumberOfChunks(chunkName);
            String filename = getWholeFileName(chunkName);
            byte[] buffer = new byte[BUFSIZE];
            FileOutputStream fos = new FileOutputStream(filename);
            try {
                for (int i=0; i<nChunks; i++) {
                    FileInputStream fis = new FileInputStream(chunkFileName(filename, i, nChunks, n));
                    try {
                        copyStream(fis, buffer, fos, -1);
                    } finally {
                        Closer.closeSilently(fis);
                    }
                }
            } finally {
                Closer.closeSilently(fos);
            }
        }
    }
    public static boolean deleteAllChunks(String chunkName) {
        boolean res = true;
        int n = chunkIndexLen(chunkName);
        if (n>0) {
            int nChunks = getNumberOfChunks(chunkName);
            String filename = getWholeFileName(chunkName);
            for (int i=0; i<nChunks; i++) {
                File f = new File(chunkFileName(filename, i, nChunks, n));
                res &= (f.delete() || !f.exists());
            }
        }
        return res;
    }
    private static long copyStream(FileInputStream fis, byte[] buffer, FileOutputStream fos, long maxAmount) throws IOException {
        long chunkSizeWritten;
        for (chunkSizeWritten=0; chunkSizeWritten<maxAmount || maxAmount<0; ) {
            int toRead = maxAmount < 0 ? buffer.length : (int)Math.min(buffer.length, maxAmount - chunkSizeWritten);
            int lengthRead = fis.read(buffer, 0, toRead);
            if (lengthRead < 0) {
                break;
            }
            fos.write(buffer, 0, lengthRead);
            chunkSizeWritten += lengthRead;
        }
        return chunkSizeWritten;
    }
}

借用Closer herefrom org.apache.logging.log4j.core.util

答案 5 :(得分:0)

对文件进行二进制比较时会发生什么。例如与差异。你看到第一个文件后有什么区别吗?

您可以尝试分解文本TXT文件吗?如果有字节不合适,那么出错的原因应该更明显。例如重复的块/文件/或充满nul字节的数据。 ??

编辑:正如其他人注意到的那样,您没有按特定顺序阅读文件。你可以做的是使用填充文件号,如。

newName = String.format("%s.part%09d", fname, nChunks - 1);

这将按数字顺序为您提供最多10亿个文件。

当您阅读文件时,您需要确保它们已排序。

Arrays.sort(files);
for (File file : files) {

使用其他人建议的自定义比较器会减少填充数字的大小,但能够按名称排序以获得正确的顺序可能会很好。例如在探险家。

答案 6 :(得分:0)

需要拆分文件名和目标文件大小(以字节为单位)形成用户并将其拆分为子文件,它适用于所有类型的文件,如(.bin,.jpg,.rar)

import java.io.*;
class split{
public static void main(String args[])throws IOException {
String a;
int b;
long len;
Console con=System.console();
System.out.println("Enter File Name: ");
File f=new File(con.readLine());
System.out.println("Enter Destination File Size: ");  
b=Integer.parseInt(con.readLine());
FileInputStream fis=new FileInputStream(f);
len=f.length();
int c=(int)len/b;
if(((int)len%b)!=0)
c++;
for(int i=0;i<c;i++){
File f1=new File(i+""+"."+f);
FileOutputStream fos=new FileOutputStream(f1);
for(int j=0;j<b;j++){   
int ch;
if((ch=fis.read())!=-1)
fos.write(ch); } }
fis.close();
System.out.println("Operation Successful"); }}

和另一个程序将合并所有拆分文件。它只采用拆分文件名并合并所有文件。

import java.io.*;
class merge{
static int i;
public static void main(String args[])throws IOException{
String a;
int b;
long len;
Console con=System.console();
System.out.println("Enter File to be retrived: ");
File f=new File(con.readLine());
FileOutputStream fos=new FileOutputStream(f,true);
try {
File f1=new File(i+""+"."+f);
while((f1.exists())!=false) {
int ch;
FileInputStream fis=new FileInputStream(i+""+"."+f);
i++;
while((ch=fis.read())!=-1){
fos.write(ch);  }}}
catch(FileNotFoundException e1){} }}