2010-12-13 46 views
16

Estoy tratando de dividir un archivo binario (como video/audio/imagen) en pedazos de 100 kb cada uno y luego unir esos fragmentos para recuperar el archivo original. Mi código parece estar funcionando, en el sentido de que divide el archivo y une los fragmentos, el archivo que obtengo es del mismo tamaño que el original. Sin embargo, el problema es que los contenidos se truncan, es decir, si se trata de un archivo de video, se detiene después de 2 segundos, si se trata de un archivo de imagen, entonces solo la parte superior parece correcta.Dividir y unir un archivo binario en java

Aquí está el código que estoy utilizando (me pueden enviar el código completo si se quiere):

para dividir:

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; 

Y para unirse a archivo, puse los nombres de todos los trozos de una lista, a continuación, ordenar por nombre y luego ejecute el siguiente código:

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; 

Respuesta

10

que puede detectar sólo 2 errores potenciales en el código:

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

lo anterior falla cuando el el archivo tiene más de 2GB ya que int no puede contener más.

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

Un nombre de archivo así construido debe ordenarse de una manera muy específica. Cuando se utiliza la clasificación de cadenas por defecto, name.part10 vendrá antes que name.part2.Desea proporcionar un Comparator personalizado que extrae y analiza el número de pieza como un int y luego compare con eso.

+0

El archivo es mucho menos de 2 GB, pero tiene razón sobre la parte de clasificación, está tomando 0,1,10,11,12 ..., 2,20, etc. Supongo que está estropeando esto –

+0

¡Esto funciona! ¡Muchas gracias! –

+0

De nada. – BalusC

0

¿Qué pasa cuando se hace una comparación binaria de los archivos. p.ej. con diff ¿Ves una diferencia después del primer archivo?

¿Puedes intentar romper un archivo de texto TXT? si hay bytes fuera de lugar, debería ser más obvio lo que está fallando. p.ej. un bloque/archivo/datos repetidos lleno de nulos bytes. ??

EDITAR: Como otros han notado, usted lee los archivos sin ningún orden en particular. Lo que puedes hacer es usar un número de archivo acolchado como.

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

Esto le dará hasta 1 mil millones de archivos en orden numérico.

Cuando lea los archivos, debe asegurarse de que estén ordenados.

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

El uso de un comparador personalizado como otros tienen sugerir que reduciría el tamaño de los números acolchadas, pero puede ser agradable ser capaz de clasificar por su nombre para conseguir el orden correcto. p.ej. en el explorador

+0

Solo una pequeña corrección: debe reemplazar ".part" dentro del formato con "% s" o eliminar el parámetro ".part". –

+0

@Sergey, gracias por ese punto. –

3

Y para unirse a archivo, puse los nombres de todos los trozos en una lista, a continuación, ordenar por nombre y luego ejecute el siguiente código:

Pero sus nombres son de la siguiente forma:

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

Piense cuidadosamente sobre lo que sucede si tiene 11 o más piezas. ¿Qué cadena viene primero en orden alfabético: ".part10" o ".part2"? (Respuesta:" .part10" , ya que '1' viene antes de '2' en la codificación de caracteres.)

+0

Esto funciona! ¡Muchas gracias! –

1

¿Hay más de 10 fragmentos? Entonces el programa concatenará * .part1 + * .part10 + * .part2 y así sucesivamente.

+0

¡Muchas gracias! ¡Realmente aprecio tu ayuda! –

1

para dividir el archivo: ----->

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

} 

} 
0

que se necesita nombre de archivo tamaño dividir el archivo & de destino (en bytes) formulario de usuario y dividirlo en subarchivos su trabajo para todo tipo de archivos como (.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"); }} 

y otro programa combinará toda la división files.It tomar el nombre de archivo sólo dividir y fusionar todos los archivos.

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){} }} 
+0

debe formatear su código un poco mejor – AbcAeffchen

0
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; 
    } 
} 

Borrow Closerhere o from org.apache.logging.log4j.core.util.

Cuestiones relacionadas