Unix 我如何区分';二进制';和';文本';文件夹?
非正式地说,我们大多数人都知道有“二进制”文件(对象文件、图像、电影、可执行文件、专有文档格式等)和“文本”文件(源代码、XML文件、HTML文件、电子邮件等) 一般来说,您需要知道文件的内容才能对它做任何有用的事情,并且形成这样的观点:如果编码是“二进制”或“文本”,那么这并不重要。当然,文件只存储字节数据,所以它们都是“二进制”的,“文本”在不知道编码的情况下没有任何意义。然而,谈论“二进制”和“文本”文件仍然是有用的,但为了避免用这种不精确的定义冒犯任何人,我将继续使用“恐吓”引号 但是,有各种工具可以处理范围广泛的文件,实际上,您希望根据文件是“文本”还是“二进制”来执行不同的操作。例如,在控制台上输出数据的任何工具。纯“文本”看起来不错,而且很有用二进制数据会把你的终端弄乱,而且通常是没有用的。GNUGREP在确定是否应该向控制台输出匹配项时,至少使用了这种区别Unix 我如何区分';二进制';和';文本';文件夹?,unix,language-agnostic,ascii,binaryfiles,file-format,Unix,Language Agnostic,Ascii,Binaryfiles,File Format,非正式地说,我们大多数人都知道有“二进制”文件(对象文件、图像、电影、可执行文件、专有文档格式等)和“文本”文件(源代码、XML文件、HTML文件、电子邮件等) 一般来说,您需要知道文件的内容才能对它做任何有用的事情,并且形成这样的观点:如果编码是“二进制”或“文本”,那么这并不重要。当然,文件只存储字节数据,所以它们都是“二进制”的,“文本”在不知道编码的情况下没有任何意义。然而,谈论“二进制”和“文本”文件仍然是有用的,但为了避免用这种不精确的定义冒犯任何人,我将继续使用“恐吓”引号 但是,
所以,问题是,如何判断文件是“文本”还是“二进制”?更进一步地说,在类似Linux的文件系统上,您如何判断?我不知道有任何文件系统元数据指示文件的“类型”,因此,通过检查文件的内容,问题进一步变成了如何判断文件是“文本”还是“二进制”?为了简单起见,让我们将“文本”限制为可在用户控制台上打印的字符。特别是,您将如何实现这一点?(我认为这在这个网站上是隐含的,但我想,一般来说,指出现有的代码可以做到这一点是有帮助的,我应该指定),我并不真正想知道现有的程序可以用什么来实现这一点。好吧,如果你只是检查整个文件,看看是否每个字符都可以用
isprint(c)
打印。对于Unicode,它变得稍微复杂一些
要区分unicode文本文件
其要点是首先检查最多前四个字节:
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
这将告诉您编码。然后,您希望对文本文件中的其余字符使用
iswprint(c)
。对于UTF-8和UTF-16,您需要手动解析数据,因为单个字符可以由可变的字节数表示。另外,如果你真的是anal,你会想使用你平台上可用的语言环境变量iswprint
。大多数试图区分差异的程序都使用启发式方法,比如检查文件的前n个字节,看看这些字节是否都符合“文本”的条件(即,它们是否都在可打印ASCII字符的范围内)。为了更好地区分,在类似UNIX的系统上总是有“file”命令。您可以使用file
命令。它对文件(man file
)进行一系列测试决定它是二进制还是文本。如果需要从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
您可以使用
file --mime FILENAME
Linux上的缩写是file-i
,macOS上的缩写是file-i
(大写i)(参见注释)
如果它以
text/
开头,则为文本,否则为二进制。唯一的例外是XML应用程序。您可以通过在文件类型末尾查找+XML
来匹配这些应用程序。一个简单的检查是它是否有\0
字符。文本文件没有这些字符。我公司生产的电子表格软件可以读取f二进制文件格式以及文本文件
我们首先查看我们识别的a的前几个字节。如果我们不识别我们读取的任何二进制类型的幻数,那么我们查看文件的前2K字节,看看它是一个,还是一个在当前主机操作系统中编码的文本文件。如果它没有通过这些测试,我们假设t这不是一个我们可以处理并引发适当异常的文件。如前所述*nix操作系统在file命令中具有此功能。此命令使用一个配置文件,该文件定义了许多常用文件结构中包含的幻数 这个名为magic的文件历史上存储在/etc中,但在某些发行版上可能存储在/usr/share中。magic文件定义了文件中已知值的偏移量,然后可以检查这些位置以确定文件的类型 可以通过查阅相关手册页面(man magic)找到magic文件的结构和说明 对于一个实现,可以在其自身中找到,但是确定其是否为可读文本的file命令的相关部分如下所示
/* 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 */
}
/*在查找令牌之前,请确保我们正在处理ascii文本*/
对于(i=0;i
Perl有一个不错的启发式方法。使用-B
操作符测试二进制文件(与其相反的是,-T
测试文本文件)。下面是一行代码来列出文本文件:
$ find . -type f -print0 | perl -0nE 'say if -f and -s _ and -T _'
(请注意,没有前面的美元的下划线是正确的(RTFM)。这是一个老话题,但也许有人会发现这很有用。 如果您必须在脚本中确定某个内容是否为文件,则可以简单地执行以下操作:
if file -i $1 | grep -q text;
then
.
.
fi
这将获得文件类型,使用无提示grep,您可以决定它是否为文本。您可以使用
libmagic
,这是Unix文件
命令行的库版本
许多语言都有包装纸
$ grep -rIl ''
$ grep -rIL ''
$ grep -qI '' FILE