2010-12-13 44 views
16

Tôi đang cố gắng chia một tệp nhị phân (như video/audio/hình ảnh) thành từng đoạn 100kb và sau đó nối các đoạn đó lại để lấy lại tệp gốc. Mã của tôi có vẻ đang hoạt động, theo nghĩa là nó chia tệp và tham gia các phần, tệp tôi nhận được có cùng kích thước với kích thước gốc. Tuy nhiên, vấn đề là nội dung bị cắt bớt - tức là, nếu đó là tệp video thì nó dừng sau 2 giây, nếu đó là tệp hình ảnh thì chỉ phần trên trông có vẻ chính xác.Tách và nối lại một tệp nhị phân trong java

Đây là mã tôi đang sử dụng (tôi có thể gửi toàn bộ mã nếu bạn muốn):

Đối với phân chia:

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; 

Và đối với việc gia nhập tập tin, tôi đặt tên của tất cả các khối trong một Danh sách, sau đó sắp xếp theo tên và sau đó chạy mã sau:

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; 

Trả lời

10

tôi có thể nhận ra chỉ có 2 sai lầm tiềm năng trong các mã:

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

Trên đây thất bại khi tệp vượt quá 2GB vì int không thể giữ nhiều hơn.

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

Tên tệp được xây dựng như vậy phải được sắp xếp theo cách rất cụ thể. Khi sử dụng sắp xếp chuỗi mặc định, name.part10 sẽ đến trước name.part2.Bạn muốn cung cấp một tùy chỉnh Comparator để trích xuất và phân tích số phần như là một int và sau đó so sánh bằng số đó thay thế.

+0

Tệp có kích thước nhỏ hơn 2 GB - nhưng bạn nói đúng về phần sắp xếp, nó lấy 0,1,10,11,12 ..., 2,20, v.v. - Tôi đoán điều đó đang làm rối tung lên –

+0

Những công việc này! Cảm ơn rất nhiều! –

+0

Bạn được chào đón. – BalusC

0

Điều gì xảy ra khi bạn so sánh nhị phân các tệp. ví dụ. với diff. Bạn có thấy sự khác biệt sau tệp đầu tiên không?

Bạn có thể thử chia nhỏ tệp TXT văn bản không? nếu có byte không đúng chỗ, nó sẽ rõ ràng hơn những gì đang xảy ra. ví dụ. một khối/tệp/dữ liệu lặp lại đầy đủ các byte nul. ??

EDIT: Như những người khác đã nhận thấy, bạn đọc các tệp không theo thứ tự cụ thể. Những gì bạn có thể làm là sử dụng một số tập tin độn như thế nào.

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

Điều này sẽ cung cấp cho bạn tối đa 1 tỷ tệp theo thứ tự số.

Khi bạn đọc tệp, bạn cần đảm bảo chúng được sắp xếp.

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

Sử dụng trình so sánh tùy chỉnh như những người khác đã đề xuất sẽ giảm kích thước của các số đệm nhưng có thể sắp xếp theo tên để nhận đúng thứ tự. ví dụ. trong thám hiểm.

+0

Chỉ cần chỉnh sửa một chút: bạn nên thay thế ".part" trong định dạng bằng "% s" hoặc xóa thông số ".part". –

+0

@Sergey, cảm ơn vì điểm đó. –

3

Và đối với việc gia nhập tập tin, tôi đặt tên của tất cả các khối trong một danh sách, sau đó sắp xếp nó theo tên và sau đó chạy đoạn mã sau:

Nhưng tên của bạn có dạng sau:

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

Hãy suy nghĩ cẩn thận về những gì sẽ xảy ra nếu bạn có 11 bộ phận trở lên. Chuỗi nào xuất hiện đầu tiên theo thứ tự bảng chữ cái: ".part10" hoặc ".part2"? (Trả lời:" .part10" , từ '1' đi trước '2' trong mã hóa ký tự.)

+0

Công trình này! Cảm ơn rất nhiều! –

1

Có hơn 10 đoạn không? Sau đó chương trình sẽ ghép nối * .part1 + * .part10 + * .part2 và cứ tiếp tục như vậy.

+0

Cảm ơn rất nhiều! Rất biết ơn sự giúp đỡ của bạn! –

1

Đối với việc tách các file: ----->

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

Nó mất kích thước tên file chia tập tin & đích (trong byte) hình thức sử dụng và chia nó thành Subfiles làm việc của mình cho tất cả các loại tập tin như (.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"); }} 

và một chương trình khác sẽ hợp nhất tất cả các chia files.It lấy tên file chỉ tách và hợp nhất tất cả các file.

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

bạn nên định dạng mã của mình tốt hơn một chút – 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; 
    } 
} 

Mượn Closerhere hoặc from org.apache.logging.log4j.core.util.

Các vấn đề liên quan