Подтвердить что ты не робот

Разделить и объединить двоичный файл в java

Я пытаюсь разделить двоичный файл (например, видео/аудио/изображение) на куски по 100 кбайт каждый, а затем присоединить эти фрагменты назад, чтобы вернуть исходный файл. Мой код, похоже, работает, в том смысле, что он делит файл и соединяет куски, и файл, который я возвращаю, имеет тот же размер, что и оригинал. Однако проблема заключается в том, что содержимое усекается - то есть, если это видеофайл, он останавливается через 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;

И для присоединения к файлу я помещаю имена всех кусков в список, а затем сортирую их по имени и затем запускаю следующий код:

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;
4b9b3361

Ответ 1

Я могу заметить только 2 возможных ошибки в коде:

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

Вышеуказанное не удается, если файл превышает 2 ГБ, поскольку int не может содержать больше.

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

Имя файла, которое построено таким образом, должно быть отсортировано очень определенным образом. При использовании сортировки строк по умолчанию name.part10 будет отображаться до name.part2. Вы хотите предоставить пользовательский Comparator, который извлекает и анализирует номер детали как int, а затем сравнивает это.

Ответ 2

И для присоединения к файлу я помещаю имена всех кусков в список, а затем сортирую их по имени и затем запускаю следующий код:

Но ваши имена имеют следующую форму:

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

Подумайте о том, что произойдет, если у вас есть 11 или более частей. Какая строка начинается в алфавитном порядке: ".part10" или ".part2"? (Ответ: ".part10", так как "1" предшествует "2" в кодировке символов.)

Ответ 3

Есть ли более 10 кусков? Затем программа будет конкатенировать *.part1 + *.part10 + *.part2 и т.д.

Ответ 4

Для разделения файла: ----- >

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

}

}

Ответ 5

Что происходит, когда вы выполняете двоичное сравнение файлов. например с diff. Вы видите разницу после первого файла?

Можете ли вы попытаться разбить текстовый файл TXT? если есть байты неуместны, должно быть более очевидно, что происходит неправильно. например повторяющийся блок/файл/или данные, заполненные nul байтами.??

EDIT: Как заметили другие, вы читаете файлы в определенном порядке. Что вы можете сделать, это использовать проложенный номер файла, например.

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

Это даст вам до 1 миллиарда файлов в числовом порядке.

Когда вы читаете файлы, вам необходимо убедиться, что они отсортированы.

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

Использование пользовательского компаратора, как утверждают другие, уменьшит размер заполненных номеров, но может быть неплохо иметь возможность сортировать по имени, чтобы получить правильный порядок. например в проводнике.

Ответ 6

Требуется разбить имя файла и размер целевого файла (в байтах) и разбить его на подфайлы, работающие для всех типов файлов, таких как (.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){} }}

Ответ 7

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 здесь или из org.apache.logging.log4j.core. Util.