快速判断文件是文本文件或二进制文件 .

来源:互联网 发布:c 语言declaration 编辑:程序博客网 时间:2024/04/28 09:02
 

判断一个文件是文本文件还是二进制文件可以帮助压缩软件针对不同文件选择对应的算法,那么如何判断一个文件是是文本还是二进制呢?

旧版本的pkzip使用的方法是:如果80%以上的字节都落在7..127的范围里,就认为它是文本文件,否则它就是二进制文件。代码如下:

 

 

view plaincopy to clipboardprint?
  1. int isPlainText(const char *filename)  
  2. {  
  3.   FILE *fp = fopen(filename, "rb");  
  4.   long file_length;  
  5.   long plain_text_char_count = 0;  
  6.   long binary_char_count = 0;  
  7.   int read_len;  
  8.   unsigned char byte;  
  9.   fseek(fp, 0, SEEK_END);  
  10.   file_length = ftell(fp);  
  11.   fseek(fp, 0, SEEK_SET);  
  12.   while ((read_len = fread(&byte, 1, 1, fp)) > 0)  
  13.   {  
  14.     if (byte >= 7) plain_text_char_count++;  
  15.     else binary_char_count++;  
  16.   }  
  17.   fclose(fp);  
  18.   return (plain_text_char_count / file_length > 0.8) ? 1 : 0;  
  19. }  
 

 

 

但是这个方法有一些缺陷,比如有的文件里包含了一些128..255里的字母,比如希腊语字母,或者这个文件使用其他语言编码包括了汉字等多字节字符甚至使用Unicode编码就无法判断了。所以下面介绍一种用在zlib上的新方法,,可以判断ASCII,Unicode,以及其他一些宽字符集。

 

这个算法把一个字节的数据放入三个名单:

白名单:

9 (TAB), 10 (LF), 13 (CR), 32..255

灰名单:

7 (BEL), 8 (BS), 11(VT), 12 (FF), 26 (SUB), 27 (ESC)

黑名单:

0..6, 14..31

 

判断的方法是:

如果一个文件包含至少一个白名单中的字节而且不包含一个黑名单中的字节,那么它就是文本文件,否则它是二进制文件。

算法原理很简单,凡是出现了黑名单中的字节的文件几乎只可能是二进制文件,而普通的文本文件几乎不可能出现这些字节,即使是Unicode等多字节编码也会设置高位的标记字符以实现兼容ASCII。

代码如下:

 

 

view plaincopy to clipboardprint?
  1. int isPlainText2(const char *filename)  
  2. {  
  3.   FILE *fp = fopen(filename, "rb");  
  4.   long white_list_char_count = 0;  
  5.   int read_len;  
  6.   unsigned char byte;  
  7.   while ((read_len = fread(&byte, 1, 1, fp)) > 0)  
  8.   {  
  9.     if (byte == 9 || byte == 10 || byte == 13 || (byte >= 32 && byte <= 255))  
  10.       white_list_char_count++;  
  11.     else if ((byte <= 6) || (byte >= 14 && byte <= 31))  
  12.       return 0;  
  13.   }  
  14.   fclose(fp);  
  15.   return (white_list_char_count >= 1) ? 1 : 0;  
  16. }  
 

 

参考资料:<<A Fast Method for Identifying Plain Text Files>> by Cosmin Truta updated in 2006-May-28