从一个File.ReadAllBytes (byte[])中移除字节顺序标记

14

我有一个HTTPHandler正在读取一组CSS文件并将它们合并,然后使用GZip对它们进行压缩。但是,一些CSS文件包含一个字节顺序标记(由于TFS 2005自动合并中的错误),在FireFox中BOM被读入作为实际内容的一部分,导致我的类名出现问题等。如何剥离BOM字符?是否有一种简单的方法可以在不手动浏览字节数组查找""的情况下完成?


BOM出现在实际文本中还是只出现在开头?如果不是在数据开头,我会感到惊讶 - 在这种情况下,忽略前3个字节(假设是UTF-8)就可以解决问题。 - Jon Skeet
顺便提一下,您可以在[Notepad ++](http://notepad-plus.sourceforge.net/uk/site.htm)中打开文件并保存它们而不带字节顺序标记。这就是我在[这个问题](https://dev59.com/cHVC5IYBdhLWcg3wcwsm)中所做的。 - George Stocker
2
我在遇到这个问题后写了以下帖子。基本上,我没有使用BinaryReader类读取文件内容的原始字节,而是使用StreamReader类的特定构造函数,该函数自动从我尝试检索的文本数据中删除字节顺序标记字符。 - Andrew Thompson
5个回答

8

通过一个示例来扩展 Jon的评论

var name = GetFileName();
var bytes = System.IO.File.ReadAllBytes(name);
System.IO.File.WriteAllBytes(name, bytes.Skip(3).ToArray());

7
然而,一些CSS文件包含字节顺序标记(BOM)。由于上面的代码没有检查是否存在BOM就跳过它,因此会出现问题。其中一些CSS文件包含BOM。 - Pure.Krome
但是UTF-32具有4字节的BOM。在这种情况下,您必须跳过4个字节。 - Legends

6

将JaredPar示例扩展到递归遍历子目录:

using System.Linq;
using System.IO;
namespace BomRemover
{
    /// <summary>
    /// Remove UTF-8 BOM (EF BB BF) of all *.php files in current & sub-directories.
    /// </summary>
    class Program
    {
        private static void removeBoms(string filePattern, string directory)
        {
            foreach (string filename in Directory.GetFiles(directory, file  Pattern))
            {
                var bytes = System.IO.File.ReadAllBytes(filename);
                if(bytes.Length > 2 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
                {
                    System.IO.File.WriteAllBytes(filename, bytes.Skip(3).ToArray()); 
                }
            }
            foreach (string subDirectory in Directory.GetDirectories(directory))
            {
                removeBoms(filePattern, subDirectory);
            }
        }
        static void Main(string[] args)
        {
            string filePattern = "*.php";
            string startDirectory = Directory.GetCurrentDirectory();
            removeBoms(filePattern, startDirectory);            
        }       
    }
}

在发现使用基本的PHP下载文件时,UTF-8 BOM会破坏文件后,我需要那段C#代码。


3
var text = File.ReadAllText(args.SourceFileName);
var streamWriter = new StreamWriter(args.DestFileName, args.Append, new UTF8Encoding(false));
streamWriter.Write(text);
streamWriter.Close();

看这段代码,理论上它应该能够工作。但是,我很惊讶它保存的文件格式是ANSI。 - VJOY
new UTF8Encoding(false) 参数表示是否添加BOM。 - Guy Lowe

1

另一种方法是假设使用UTF-8转换为ASCII。

File.WriteAllText(filename, File.ReadAllText(filename, Encoding.UTF8), Encoding.ASCII);

0

对于较大的文件,使用以下代码;内存高效!

StreamReader sr = new StreamReader(path: @"<Input_file_full_path_with_byte_order_mark>", 
                    detectEncodingFromByteOrderMarks: true);

StreamWriter sw = new StreamWriter(path: @"<Output_file_without_byte_order_mark>", 
                    append: false, 
                    encoding: new UnicodeEncoding(bigEndian: false, byteOrderMark: false));

var lineNumber = 0;
while (!sr.EndOfStream)
{
    sw.WriteLine(sr.ReadLine());
    lineNumber += 1;
    if (lineNumber % 100000 == 0)
        Console.Write("\rLine# " + lineNumber.ToString("000000000000"));
}

sw.Flush();
sw.Close();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接