最近写一个程序用于读取STL文件(一种三维文件格式),并显示出来。STL文件存储格式有一个特殊点就是分两种类型,一种是ASCII文件类型,一种是二进制文件类型。ASCII文件类型的,里面就是一些字符串,描述了三维三角面片的坐标和法向量。二进制文件和ASCII基本一致,不过是按照二进制的方式按位来读取,并且有文件头的描述。
于是我遇到一个难题,就是如何判断STL文件是字符串格式的还是二进制格式的。
在解决该问题的过程中,我跳出该问题,上升到所有文件存储类型的判断。
严格的说,所有文件在磁盘上的存储都是二进制的,这里说说的二进制的判断,我认为就是判断该文件是否为可理解的。一串字符是可理解的,但一串类似0101001的代码是无法理解的(再简单点说:用记事本打开你能看懂的)。
我再在网上查阅了一下,发现了好几种解决方法,现在罗列一下,各位可以根据不同情况选择使用:
1、判断字符范围。
该方式主要是针对英文字符的,如果文件中有中文字符就会判断失败。比如:
char c; f.read(&c, sizeof(c)); if (c < 32 && c != 9 && c != 10 && c != 13) { return; }
该方式针对256以下的字符问题都不大,一旦遇到双字节中文就会出现c为负数的情况,导致判断失败。该方法不适合我。
2、判断有没有char(0)字符。
二进制文件基本上都会有char(0),注意,是“基本上” 。
我尝试通过这个方式来判断,发现判断正确率很高,我手头的二进制STL文件都能够判断正确,但是总觉得这种方式不够保险,如果刚好某个二进制文件没有char(0)怎么办???
3、文件大小对比法。
以文本方式 打开文件,取一段数据(比如1024字节),存为string,再写入tmp文件,如果新文件的大小还是1024字节,应该就是文本文件了。否则就是二进制文件。
该方法我没有认证,但是纯粹从描述上来说,还是比较有效的。以我的理解,该方法在本质上还是方法1和方法2的结合,相比方法1来说,方便了中文字符的判断,相比方法2来说,更为保险一些。其本质就是通过将二进制文件转换为字符串,将一些无效字符过滤掉(比如char(0),回车等等),导致大小发生变化。但同样的该方法也有漏洞,如果二进制文件中刚好没有回车,没有char(0)怎么办???
4、无效字符比例法。
该方法是基于方法1的一种概率判断,遍历文件中的所有字符,对方法1中认定的无效字符进行计数,如果无效字符数量达到一定比例(这个比例值是经验值,根据自己的程序运行环境自由设定),则认为是二进制文件。
同方法1一样,无法对中文字符进行有效的判断,一个全为中文的文本文件,肯定会被认定为二进制文件。
5、严格对比法。
逐字节读取,然后满足以下任何一个条件那么就是二进制文件: 1)所读取字节大于127并且小于160; 2)所读取字节大于等于160并且不成对出现;(注:大于等于160并成对出现的是汉字,其他UNICODE字符集编码格式不是很清楚) 3)所读取字节小于32并且不等于9(TAB)、10(换行) (注: 10 是UNIX格式文本换行) 4)所读取字节小于32并且等于13(回车)但是之后的字节并不是10(换行) (注:13 10 是DOS格式文本换行)
该方法我没有验证,但是感觉是最严谨的,也是判断最复杂的,效率最低的,一个较大的文件判断起来肯定会很慢。
最终,根绝我的应用环境,我采用了方法2,对于STL文件来说,是一种十分有效的判断方式,正确率极高,效率也十分的快。
留下此文以作备份,方便以后查阅!!!