如何在C#中确定一个文件是二进制还是文本?
如何确定文件是二进制还是文本?
背景:
我一直在研究和探索这个问题的解决方法。然而,我期望它是简单或稍微复杂一些的。
然而,大多数尝试提供了复杂的解决方案,涉及Unicode、UTF系列、BOM、编码和字节顺序等。在这个过程中,我还涉及了ASCII表和代码页。
无论如何,我根据流读取器和自定义控制字符检查的思路提出了一种解决方案。
它考虑了论坛和其他地方提供的各种提示和技巧,例如:
1. 检查很多控制字符,例如寻找多个连续的空字符。
2. 检查UTF、Unicode、编码、BOM、字节顺序等方面。
我的目标是:
1. 不依赖字节顺序、编码和其他更复杂的奥秘工作。
2. 实现相对容易,易于理解。
3. 适用于所有类型的文件。
解决方案:
我依赖于StreamReader的默认构造函数,它可以最好地确定与文件编码相关的特性,默认使用UTF8Encoding。
我创建了自己版本的检查自定义控制字符的条件,因为Char.IsControl似乎没有用处。它说:
控制字符是格式化和其他不打印的字符,例如ACK、BEL、CR、FF、LF和VT。Unicode标准将代码点从\U0000到\U001F、\U007F和从\U0080到\U009F分配给控制字符。除非应用程序另有定义,否则这些值应被解释为控制字符。它将LF和CR视为控制字符之一。
解决方案的工作原理:
我依赖于StreamReader的默认构造函数,它可以最好地确定与文件编码相关的特性,默认使用UTF8Encoding。
我创建了自己版本的检查自定义控制字符的条件,因为Char.IsControl似乎没有用处。它说:
控制字符是格式化和其他不打印的字符,例如ACK、BEL、CR、FF、LF和VT。Unicode标准将代码点从\U0000到\U001F、\U007F和从\U0080到\U009F分配给控制字符。除非应用程序另有定义,否则这些值应被解释为控制字符。它将LF和CR视为控制字符之一。
解决方案:
static void testBinaryFile(string folderPath) { Listoutput = new List (); foreach (string filePath in getFiles(folderPath, true)) { output.Add(isBinary(filePath).ToString() + " ---- " + filePath); } Clipboard.SetText(string.Join("\n", output), TextDataFormat.Text); } public static List getFiles(string path, bool recursive = false) { return Directory.Exists(path) ? Directory.GetFiles(path, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).ToList() : new List (); } public static bool isBinary(string path) { long length = getSize(path); if (length == 0) return false; using (StreamReader stream = new StreamReader(path)) { int ch; while ((ch = stream.Read()) != -1) { if (isControlChar(ch)) { return true; } } } return false; } public static bool isControlChar(int ch) { return (ch > Chars.NUL && ch < Chars.BS) || (ch > Chars.CR && ch < Chars.SUB); } public static class Chars { public static char NUL = (char)0; // Null char public static char BS = (char)8; // Back Space public static char CR = (char)13; // Carriage Return public static char SUB = (char)26; // Substitute }
如果您尝试以上解决方案,请告诉我它对您是否有效。
其他有趣和相关的链接:
- About UTF and BOM on Unicode.org
- Unicode sample files
- How to detect the character encoding of a text file and
- Detect file encoding in Csharp
getSize函数缺失。感谢您的代码。重要的部分已经被使用并且测试结果看起来很好。
我真的很喜欢这个解决方案没有阅读整个文件。这样就可以更容易地运行观察整个目录的工具,该目录可能包含50 MB的视频文件。
您可以使用new FileInfo(path).Length来获取文件大小。
它有助于确保编码。我在marketplace.visualstudio.com/…中编写了一个工具,用于确认编码,它使用了您的解决方案。
谢谢。对我有用,只有一个问题。我拿了一个XML文件,在记事本中打开并另存为Unicode(还添加了一些外文字符)。我将文件存储在MySQL数据列的博客或文本字段中,然后稍后将其写回磁盘。
谢谢,对我有用。文件保存到网络驱动器上,有时会被填充为所有空字符。
问题的出现的原因是如何确定一个文件是二进制文件还是文本文件。解决方法是通过检查文件中的控制字符和零字节的存在来判断。二进制文件通常包含大量的零字节,而文本文件很少包含零字节。如果需要考虑本地化问题,还需要检查多字节模式。然而,无论如何,仍然存在一种情况,就是二进制文件可能看起来像文本文件,反之亦然。根据作者的经验,他通过查找连续的零字节来确定一个文件是二进制文件还是文本文件。他尝试了4个连续的零字节,发现大多数二进制文件都有很多连续的零字节,所以这个方法对于大多数文件有效。但是,有一些.png文件的连续四个零字节的检测失败了,所以他尝试了两个连续的零字节,这个方法效果更好。如果文件是ASCII或UTF-8编码的文本文件,那么只需要找到一个零字节就足以确定它不是二进制文件。这种方法对于UTF-16和UTF-32文件会失效,但大多数文本编辑器也会有同样的问题。