使用C#编辑二进制文件中的文本

3

我有一个二进制文件(即包含0x00到0xFF之间值的字节)。文件中还有ASCII字符串(例如,“Hello World”),我想使用正则表达式查找并编辑它们。然后,我需要将编辑后的文件写出,使其与旧文件完全相同,但已执行了我的ASCII编辑。如何实现?

        byte[] inbytes = File.ReadAllBytes(wfile);
        string instring = utf8.GetString(inbytes);
        // use Regex to find/replace some text within instring
        byte[] outbytes = utf8.GetBytes(instring);
        File.WriteAllBytes(outfile, outbytes);

即使我没有进行任何编辑,输出文件仍然与输入文件不同。发生了什么事情,我应该怎么做才能达到我想要的结果?
编辑:好的,我正在尝试使用提供的建议,并且在实际实现时遇到了困难。下面是我的示例代码:
        string infile = @"C:\temp\in.dat";
        string outfile = @"C:\temp\out.dat";
        Regex re = new Regex(@"H[a-z]+ W[a-z]+");  // looking for "Hello World"
        byte[] inbytes = File.ReadAllBytes(infile);
        string instring = new SoapHexBinary(inbytes).ToString();
        Match match = re.Match(instring);
        if (match.Success)
        {
            // do work on 'instring'
        }
        File.WriteAllBytes(outfile, SoapHexBinary.Parse(instring).Value);

很显然,我知道这样做不会返回任何匹配结果,但如果我将我的正则表达式转换为字符串(或其他格式),那么我就无法使用Match等函数。有什么好的建议吗?谢谢!

2
你没有说明输出与输入有何不同,但如果其中包含二进制数据,我想输出会有很大的变化。你不能将一个二进制文件转换为UTF8并期望二进制数据能够完好无损地通过。 - Robert Harvey
3
用正则表达式编辑二进制文件吗?不要尝试这样做。 - L.B
Robert:输出结果会有所不同,因为一些字节值会被更改。例如,输入文件中的“03DC”会在输出文件中更改为“FDFF”(这是使用Unicode编码而不是utf8)。 - Barry Dysert
1
Justin:正则表达式非常相关,因为有许多ASCII字符串需要查找/替换。使用正则表达式要容易得多。 - Barry Dysert
但是你并没有询问关于如何在这方面使用正则表达式。你正在尝试编辑嵌入二进制文件中的文本字符串。正则表达式并不足够相关,不能出现在标题中或用它来标记问题。实际上,它在这里的唯一相关性就是为了提供上下文。 - Justin Morgan
显示剩余7条评论
3个回答

2

并非所有的二进制字符串都是有效的UTF-8字符串。当你试图将二进制解释为UTF-8字符串时,无法解释的字节可能会被破坏。基本上,如果整个文件不是编码文本,则将其解释为编码文本将不会产生明智的结果。


谢谢。我怀疑“整个文件不是编码文本”。所以,是否没有办法读取二进制文件、编辑一些ASCII字符串并写入新的二进制文件而不使字节混乱? - Barry Dysert
我相信有这样的编码方式存在。可能并不是最好的方式,但可以采用某些8位编码来往返任意二进制数据。Windows-1252似乎不是这样一种编码方式。 - Thom Smith

1

与处理二进制文件相比,另一种方法是将其转换为十六进制字符串,对其进行操作(可以使用正则表达式),然后保存回去。

byte[] buf = File.ReadAllBytes(file);
var str = new SoapHexBinary(buf).ToString();

//str=89504E470D0A1A0A0000000D49484452000000C8000000C808030000009A865EAC00000300504C544......
//Do your work

File.WriteAllBytes(file,SoapHexBinary.Parse(str).Value);

PS:命名空间:System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary


-1

我明白了!看看这段代码:

        string infile = @"C:\temp\in.dat";
        string outfile = @"C:\temp\out.dat";
        Regex re = new Regex(@"H[a-z]+ W[a-z]+");   // looking for "Hello World"
        string repl =  @"Hi there";

        Encoding ascii = Encoding.ASCII;
        byte[] inbytes = File.ReadAllBytes(infile);
        string instr = ascii.GetString(inbytes);
        Match match = re.Match(instr);
        int beg = 0;
        bool replaced = false;
        List<byte> newbytes = new List<byte>();
        while (match.Success)
        {
            replaced = true;
            for (int i = beg; i < match.Index; i++)
                newbytes.Add(inbytes[i]);
            foreach (char c in repl)
                newbytes.Add(Convert.ToByte(c));
            Match nmatch = match.NextMatch();
            int end = (nmatch.Success) ? nmatch.Index : inbytes.Length;
            for (int i = match.Index + match.Length; i < end; i++)
                newbytes.Add(inbytes[i]);
            beg = end;
            match = nmatch;
        }
        if (replaced)
        {
            var newarr = newbytes.ToArray();
            File.WriteAllBytes(outfile, newarr);
        }
        else
        {
            File.WriteAllBytes(outfile, inbytes);
        }

这样是行不通的。这段代码的输出将会是 63,0,63Encoding ascii = Encoding.ASCII; byte[] inbytes = new byte[] {255,0,255 }; string instr = ascii.GetString(inbytes); var outbytes = ascii.GetBytes(instr); - L.B
Barry,你可能会丢失128个字节以上的数据。 - L.B
我感谢您的警告,虽然我无法解释,但我的文件有很多大于128的值(例如81、9A、AE)。 - Barry Dysert
“我无法解释,”巴里,“二进制数据是二进制,尝试使用任何编码将其转换为字符串将导致某些数据的丢失。我不认为这是正确的方法。但是,无论如何,这是你的选择。” - L.B

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