2009-03-07 42 views

Trả lời

16

Không có cách nào đảm bảo, nhưng dưới đây là một vài khả năng:

1) Tìm tiêu đề trên tệp. Thật không may, tiêu đề là tập tin cụ thể, do đó, trong khi bạn có thể tìm ra rằng đó là một tập tin RAR, bạn sẽ không nhận được câu trả lời chung chung hơn cho dù đó là văn bản hoặc nhị phân.

2) Đếm số ký tự so với các loại không phải ký tự. Các tệp văn bản sẽ chủ yếu là các ký tự chữ cái trong khi các tệp nhị phân - đặc biệt là các tệp nén như rar, zip và như vậy - sẽ có xu hướng có các byte được biểu diễn đồng đều hơn.

3) Tìm kiếm mẫu lặp lại thường xuyên của các dòng mới.

1

Bạn có thể thử công cụ DROID.

3

Nếu tập tin bao gồm các byte 0x09 (tab), 0x0A (feed line), 0x0c (mẫu thức ăn chăn nuôi), 0x0D (carriage return), hoặc 0x20 qua 0x7E, sau đó nó có thể là ASCII text .

Nếu tệp chứa bất kỳ ký tự điều khiển ASCII nào khác, 0x00 đến 0x1F không bao gồm ba ký tự ở trên, thì đó có thể là dữ liệu nhị phân.

Văn bản UTF-8 tuân theo một mẫu rất cụ thể cho bất kỳ byte nào có bit thứ tự cao, nhưng mã hóa có độ dài cố định như ISO-8859-1 thì không. UTF-16 thường có thể chứa byte rỗng (0x00), nhưng chỉ ở mọi vị trí khác.

Bạn sẽ cần một heuristic yếu hơn cho bất kỳ điều gì khác.

9

Hãy xem thư viện JMimeMagic.

jMimeMagic là thư viện Java dành cho xác định loại tệp MIME hoặc luồng.

+0

Thư viện thú vị, nhưng làm cách nào để giúp đỡ? Nó cho bạn biết loại mime, nhưng không cho dù đó là nhị phân hay văn bản. – Adam

+0

@Adam Tôi không hiểu câu hỏi của bạn? Bạn có thể suy ra từ chính loại MIME cho dù tệp đó là nhị phân hay không, phải không? I E. nếu kiểu là 'text/plain', nó phải là một tệp văn bản. – dhiller

+0

OK, tôi đã bị cùn. Những gì tôi có nghĩa là bạn vẫn phải viết thêm logic để giải thích các loại mime như nhị phân hoặc văn bản. 'văn bản/đồng bằng' không phải là loại mime dựa trên văn bản duy nhất. – Adam

3

Để cho bạn biết, tôi đã chọn một con đường hoàn toàn khác. Tôi trường hợp của tôi, chỉ có 2 loại tập tin, cơ hội mà bất kỳ tập tin nhất định sẽ là một nhị phân là cao. Vì vậy,

  1. đoán rằng tập tin được nhị phân, cố gắng làm những gì là nghĩa vụ phải được thực hiện (ví dụ deserialize)
  2. bắt ngoại lệ
  3. điều trị tập tin như văn bản
  4. nếu thất bại, cái gì là sai với tập tin bản thân
+0

Tôi nghĩ rằng đây là cách tiếp cận tốt nhất. Bạn có thực sự quan tâm đến loại tệp không? Hay bạn có quan tâm liệu bạn có thể làm những việc nhất định với nó hay không. Trong nhiều trường hợp, nếu bạn có thể làm những điều đó, bạn không cần phải thực sự biết loại đó là gì. – stackexchanger

10

Chạy file -bi {filename}. Nếu bất cứ điều gì nó trả về bắt đầu bằng 'text /', thì nó không phải là nhị phân, nếu không nó sẽ là. ;-)

+1

Có vẻ như có "ứng dụng/javascript" và "ứng dụng/xml" cũng vậy. Nhìn vào đây http://en.wikipedia.org/wiki/Internet_media_type gợi ý rằng nó không đơn giản như vậy. – Aaron

+1

Bạn có thể kiểm tra bằng 'file -i {filename}' và kiểm tra ở đó không có 'charset = binary'. –

+0

Tôi phải nói rằng tôi không hoàn toàn nghiêm túc khi tôi trả lời câu hỏi trên. Tệp văn bản chỉ là các tệp nhị phân được diễn giải theo một cách cụ thể. Nếu bạn có nghĩa là nếu một cái gì đó là US-ASCII, sau đó bạn có thể kiểm tra mỗi byte và xem nếu nó phù hợp với định nghĩa của bạn về văn bản. Nhưng có lẽ bạn có nghĩa là * bất kỳ loại * mã hóa ký tự nào. Điều đó sẽ khó hơn rất nhiều. Đặc biệt là nếu bạn yếu tố trong những người đang sử dụng nói entropy dựa trên mã hóa (ký tự xảy ra thường đòi hỏi ít bit). Mặt khác, nếu bạn có nghĩa là tất cả mọi thứ US-ASCII, thì một hình ảnh được mã hóa Base64 cũng sẽ là văn bản? –

5

tôi đã sử dụng đoạn mã này và nó hoạt động cho tiếng Anh và văn bản tiếng Đức khá tốt:

private boolean isTextFile(String filePath) throws Exception { 
    File f = new File(filePath); 
    if(!f.exists()) 
     return false; 
    FileInputStream in = new FileInputStream(f); 
    int size = in.available(); 
    if(size > 1000) 
     size = 1000; 
    byte[] data = new byte[size]; 
    in.read(data); 
    in.close(); 
    String s = new String(data, "ISO-8859-1"); 
    String s2 = s.replaceAll(
      "[a-zA-Z0-9ßöäü\\.\\*!\"§\\$\\%&/()=\\[email protected]~'#:,;\\"+ 
      "+><\\|\\[\\]\\{\\}\\^°²³\\\\ \\n\\r\\t_\\-`´âêîô"+ 
      "ÂÊÔÎáéíóàèìòÁÉÍÓÀÈÌÒ©‰¢£¥€±¿»«¼½¾™ª]", ""); 
    // will delete all text signs 

    double d = (double)(s.length() - s2.length())/(double)(s.length()); 
    // percentage of text signs in the text 
    return d > 0.95; 
} 
+2

Ý tưởng thú vị, nhưng thay vì replaceAll, thứ không cần thiết tạo ra một chuỗi mới, tôi chỉ đơn giản sử dụng vòng lặp for để đếm văn bản so với các ký tự không phải văn bản. Đặt giới hạn ở 1000 ký tự có nghĩa là nó sẽ không được * quá * tốn kém anyway, nhưng nó vẫn là một chi phí vô ích – miniBill

8

tôi làm thế này. Một chút đơn giản hơn, nhưng đối với các ngôn ngữ dựa trên tiếng Latinh, nó sẽ hoạt động tốt, với điều chỉnh tỷ lệ.

/** 
* Guess whether given file is binary. Just checks for anything under 0x09. 
*/ 
public static boolean isBinaryFile(File f) throws FileNotFoundException, IOException { 
    FileInputStream in = new FileInputStream(f); 
    int size = in.available(); 
    if(size > 1024) size = 1024; 
    byte[] data = new byte[size]; 
    in.read(data); 
    in.close(); 

    int ascii = 0; 
    int other = 0; 

    for(int i = 0; i < data.length; i++) { 
     byte b = data[i]; 
     if(b < 0x09) return true; 

     if(b == 0x09 || b == 0x0A || b == 0x0C || b == 0x0D) ascii++; 
     else if(b >= 0x20 && b <= 0x7E) ascii++; 
     else other++; 
    } 

    if(other == 0) return false; 

    return 100 * other/(ascii + other) > 95; 
} 
+1

Cảm ơn chức năng này. Một điều tôi gặp khó khăn trong việc tìm ra những gì đang xảy ra với giá trị trả về: 'return (ascii + other) * 100/other> 95;' , trừ khi tôi thiếu thứ gì đó, sẽ luôn trả về true: Chủ yếu, kích thước sẽ là '1024', như' data.length' và do đó '(ascii + other)'. Vì vậy, nếu '(ascii + khác) * 100 == 102400' thì' 102400/khác> 95' => '102400> 95 * other' =>' other <1078' Có nghĩa là cần phải lớn hơn 1078 (trong số 1024) "khác" cho điều này để trả về false, rõ ràng là không thể. Ý của bạn là gì ?: '(khác/size * 100> 95)' Hoặc tôi có thiếu gì đó không? – Inversus

+0

Tôi nghĩ bạn nói đúng. Sửa mã. –

+0

Mát mẻ. Ya, tôi đã kết thúc với điều đó. Cảm ơn lần nữa :) – Inversus

5

Sử dụng Java 7 tập tin lớp http://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType(java.nio.file.Path)

boolean isBinaryFile(File f) throws IOException { 
     String type = Files.probeContentType(f.toPath()); 
     if (type == null) { 
      //type couldn't be determined, assume binary 
      return true; 
     } else if (type.startsWith("text")) { 
      return false; 
     } else { 
      //type isn't text 
      return true; 
     } 
    } 
+3

Điều đó chỉ kiểm tra phần mở rộng tệp và không phải là nội dung tệp và do đó vô dụng. – ares

+1

Điều đó phụ thuộc vào những gì được cài đặt, theo các tài liệu. – Adam

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