2009-02-19 101 views
52

Không chính thức, hầu hết chúng ta hiểu rằng có các tệp 'nhị phân' (tệp đối tượng, hình ảnh, phim, tệp thực thi, định dạng tài liệu độc quyền, v.v.) và tệp 'văn bản' (mã nguồn, tệp XML, tệp HTML, email, v.v.) .Làm cách nào để phân biệt giữa các tệp 'nhị phân' và 'văn bản'?

Nói chung, bạn cần phải biết nội dung của tệp để có thể làm bất kỳ điều gì hữu ích với nó và tạo quan điểm đó nếu mã hóa là 'nhị phân' hoặc 'văn bản', nó không quan trọng . Và tất nhiên các tệp chỉ lưu trữ các byte dữ liệu để chúng là tất cả 'nhị phân' và 'văn bản' không có nghĩa là bất cứ điều gì mà không biết mã hóa. Tuy nhiên, vẫn còn hữu ích khi nói về các tệp 'nhị phân' và 'văn bản', nhưng để tránh xúc phạm bất kỳ ai có định nghĩa không chính xác này, tôi sẽ tiếp tục sử dụng dấu ngoặc kép 'sợ hãi'.

Tuy nhiên, có nhiều công cụ khác nhau hoạt động trên nhiều loại tệp và về mặt thực tế, bạn muốn làm điều gì đó khác nhau dựa vào việc tệp có phải là 'văn bản' hay 'nhị phân' hay không. Một ví dụ về điều này là bất kỳ công cụ nào xuất dữ liệu trên bảng điều khiển. Plain 'text' sẽ trông ổn và hữu dụng. dữ liệu 'nhị phân' làm hỏng thiết bị đầu cuối của bạn và thường không hữu ích khi xem xét. GNU grep ít nhất sử dụng sự khác biệt này khi xác định xem nó có nên xuất khớp với giao diện điều khiển hay không.

Vì vậy, câu hỏi đặt ra là, làm cách nào để bạn biết tệp có phải là 'văn bản' hay 'nhị phân'? Và để hạn chế là hơn nữa, làm thế nào để bạn nói trên một Linux như hệ thống tập tin? Tôi không biết bất kỳ siêu dữ liệu hệ thống tập tin nào chỉ ra 'loại' của một tệp, do đó, câu hỏi tiếp tục trở thành, bằng cách kiểm tra nội dung của tệp, làm cách nào để biết đó là 'văn bản' hay 'nhị phân'? Và để đơn giản, hãy hạn chế 'văn bản' có nghĩa là các ký tự có thể in được trên bảng điều khiển của người dùng. Và cụ thể là cách bạn triển khai điều này? (Tôi nghĩ rằng điều này được ngụ ý trên trang web này, nhưng tôi đoán nó hữu ích, nói chung, được chỉ vào mã hiện có thực hiện điều này, tôi nên có quy định), tôi không thực sự sau những chương trình hiện tại tôi có thể sử dụng để làm điều này.

Trả lời

11

Phần mềm của chúng tôi đọc một số định dạng tệp nhị phân cũng như tệp văn bản.

Trước tiên, chúng tôi xem xét một vài byte đầu tiên cho số magic number mà chúng tôi nhận ra. Nếu chúng tôi không nhận ra số ma thuật của bất kỳ loại nhị phân nào mà chúng tôi đọc, thì chúng tôi xem xét tối đa 2K byte đầu tiên của tệp để xem liệu nó có phải là UTF-8, UTF-16 hoặc tệp văn bản được mã hóa trong code page hiện tại hay không của hệ điều hành máy chủ. Nếu nó không vượt qua những thử nghiệm này, chúng tôi giả định rằng nó không phải là một tệp chúng tôi có thể xử lý và ném một ngoại lệ thích hợp.

+17

bạn không nói "phần mềm của chúng tôi" là gì, làm chậm quá trình phân tích cú pháp của con người. – vwvan

4

Vâng, nếu bạn chỉ kiểm tra toàn bộ tệp, hãy xem liệu mọi ký tự có thể in được không bằng isprint(c). Nó hơi phức tạp hơn một chút đối với Unicode.

Để phân biệt tệp văn bản unicode, MSDN offers some great advice as to what to do.

Các ý chính của nó là để kiểm tra đầu tiên lên đến bốn byte đầu tiên:

EF BB BF  UTF-8 
FF FE  UTF-16, little endian 
FE FF  UTF-16, big endian 
FF FE 00 00 UTF-32, little endian 
00 00 FE FF UTF-32, big-endian 

Điều đó sẽ cho bạn biết mã hóa. Sau đó, bạn muốn sử dụng iswprint(c) cho các ký tự còn lại trong tệp văn bản. Đối với UTF-8 và UTF-16, bạn cần phân tích cú pháp dữ liệu theo cách thủ công vì một ký tự đơn có thể được biểu diễn bằng số byte thay đổi. Ngoài ra, nếu bạn thực sự hậu môn, bạn sẽ muốn sử dụng biến thể miền địa phương của iswprint nếu có sẵn trên nền tảng của bạn.

+0

Chỉ hoạt động đối với các tệp sử dụng quy tắc này. –

+0

Vâng, nếu nó không tuân theo các quy tắc đó thì nó thực sự không phải là một tập tin văn bản. Ngoại trừ mbcs, nhưng đó là một câu chuyện hoàn toàn khác. – MSN

+3

Việc chuẩn bị một BOM lên các tệp UTF-8 không được khuyến khích bởi tiêu chuẩn Unicode, và thật đáng tiếc là chúng không cấm nó hoàn toàn. Ngoài ra, những định dạng khác không cần thiết phải có một. – Deduplicator

2

Hầu hết các chương trình mà cố gắng để biết sự khác biệt sử dụng một heuristic, chẳng hạn như kiểm tra các n byte đầu tiên của tập tin và nhìn thấy nếu những byte tất cả đủ điều kiện như 'text' hay không (ví dụ, họ có tất cả sụp đổ trong phạm vi của charcters ASCII có thể in). Để phân biệt tốt hơn, luôn có lệnh 'tệp' trên các hệ thống giống UNIX.

60

Bạn có thể sử dụng lệnh file. Nó thực hiện một loạt các kiểm tra trên tập tin (man file) để quyết định xem đó là nhị phân hay văn bản. Bạn có thể xem/mượn mã nguồn của nó nếu bạn cần làm điều đó từ C.

file README 
README: ASCII English text, with very long lines 

file /bin/bash 
/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5, dynamically linked (uses shared libs), stripped 
+0

+1 Nếu đó là một hệ thống Linux, tập tin sẽ có nhiều chẩn đoán tốt hơn bất cứ điều gì bạn sẽ tự xây dựng. –

+0

Vâng, nếu tập tin có sẵn, nó sẽ là công cụ tốt nhất cho công việc. Không có câu hỏi! Ngoài ra, 'file -I' là một mẹo nhỏ gọn. Tôi đã không nghĩ đến việc bắn phá cho vấn đề cụ thể của tôi, tuy nhiên tôi không nghĩ rằng tôi có thể đối phó với chi phí hoạt động. Cảm ơn! – benno

10

Bạn có thể xác định MIME type của tập tin với

file --mime 

Các viết tắt là file -i trên Linux và file -I (vốn i) trên hệ điều hành MacOS (xem ý kiến).

Nếu bắt đầu bằng text/, đó là văn bản, nếu không thì nhị phân. Ngoại lệ duy nhất là các ứng dụng XML. Bạn có thể đối sánh chúng bằng cách tìm kiếm +xml ở cuối loại tệp.

+0

Tôi nghĩ rằng nên là "tập tin -I" (trường hợp trên). Ít nhất là theo các bài kiểm tra và trang người đàn ông của tôi. – benno

+1

Chỉ cần nhìn nó lên, trường hợp thấp hơn là chính xác trong Debian và gentoo Linux. Tệp của họ là ftp://ftp.astron.com/pub/file/file-5.00.tar.gz (hoặc một phiên bản khác). -Tôi (trên) là một tùy chọn trong cả hai. – phihag

+0

Huh, kỳ lạ. Phiên bản trên OS X (4.17) sử dụng -I (trên) và một trong các hộp Linux của tôi (4.24) sử dụng -i (thấp hơn). Làm thế nào bizzare! Tôi tự hỏi nếu nó là một OS X-ism, hoặc các tác giả chỉ đơn giản là thay đổi giao diện ở giữa phát hành điểm. – benno

1

Một kiểm tra đơn giản là nếu nó có \0 ký tự. Các tệp văn bản không có chúng.

+9

trừ khi đó là utf-16 hoặc utf32. sau đó có rất nhiều. – Breton

1

Như đã nêu trước đây hệ điều hành * nix có khả năng này trong lệnh tệp. Lệnh này sử dụng tệp cấu hình xác định số ma thuật có trong nhiều cấu trúc tệp phổ biến.

Tệp này, được gọi là ma thuật được lưu trữ trong lịch sử trong/etc, mặc dù điều này có thể nằm trong/usr/share trên một số bản phân phối. Tệp ma thuật xác định các giá trị lệch của các giá trị được biết tồn tại trong tệp và sau đó có thể kiểm tra các vị trí này để xác định loại tệp.

Cấu trúc và mô tả của file ảo thuật có thể được tìm thấy bằng cách tham khảo ý kiến ​​có liên quan của nhãn hiệu trang (người đàn ông ma thuật)

Đối với một thực hiện, cũng có thể được tìm thấy trong file.c chính nó, tuy nhiên phần có liên quan của tập tin lệnh xác định xem đó có phải là văn bản có thể đọc được hay không là sau

/* Make sure we are dealing with ascii text before looking for tokens */ 
    for (i = 0; i < nbytes - 1; i++) { 
     if (!isascii(buf[i]) || 
      (iscntrl(buf[i]) && !isspace(buf[i]) && 
      buf[i] != '\b' && buf[i] != '\032' && buf[i] != '\033' 
      ) 
      ) 
      return 0; /* not all ASCII */ 
    } 
3

Perl có một heuristic phong nha. Sử dụng toán tử -B để kiểm tra nhị phân (và đối số của nó là -T để kiểm tra văn bản). Dưới đây của bao một lớp lót để liệt kê các file văn bản:

$ find . -type f -print0 | perl -0nE 'say if -f and -s _ and -T _' 

(Lưu ý rằng những dấu gạch mà không cần một đồng đô la trước là chính xác (RTFM).)

2

nó một chủ đề cũ, nhưng có lẽ ai đó sẽ tìm thấy hữu ích này . Nếu bạn phải quyết định trong một kịch bản nếu một cái gì đó là một tập tin sau đó bạn chỉ có thể làm như thế này:

if file -i $1 | grep -q text; 
then 
. 
. 
fi 

này sẽ nhận được các loại tập tin, và với một grep im lặng, bạn có thể quyết định xem nó là một văn bản.

+0

osx có hai biến thể cho điều này: chữ thường -i sẽ in loại mà không phân loại (ví dụ: tệp, thư mục); chữ hoa -I sẽ in phân loại, tương tự như những gì bạn mong đợi trên một hệ thống Linux. Bạn sẽ muốn sử dụng chữ hoa -I để làm việc trên nền tảng đó – verboze

0

Bạn có thể sử dụng libmagic là phiên bản thư viện của dòng lệnh Unix file.

Có wrapper cho nhiều ngôn ngữ:

0

Để lis tên t tập tin văn bản trong dir/subdirs hiện tại:

$ grep -rIl '' 

Binaries:

$ grep -rIL '' 

Để kiểm tra tập tin cụ thể, hơi sửa đổi lệnh:

$ grep -qI '' FILE 

sau đó, trạng thái thoát '0' would nghĩa là tệp là văn bản; '1' - nhị phân. Có thể kiểm tra:

$ echo $?

+0

Đây là giải pháp làm việc. Xin vui lòng, giải thích lý do downvote, có lẽ tôi nên cải thiện câu trả lời bằng cách nào đó – bam

+0

Tôi đã thử nghiệm nó trên các tập tin được tạo ra bởi dd và nano. Phương pháp của bạn hoạt động tốt. Tôi cũng quan tâm lý do tại sao có phiếu giảm giá. – Daniel

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