【问题标题】:How to read mixed file of byte and string如何读取字节和字符串的混合文件
【发布时间】:2013-03-14 21:08:08
【问题描述】:

我有一个包含大量字符串行和部分字节编码数据的混合文件。 示例:

--Begin Attach
Content-Info: /Format=TIF
Content-Description: 30085949.tif (TIF File)
Content-Transfer-Encoding: binary; Length=220096
II*II* Îh  ÿÿÿÿÿÿü³küìpsMg›Êq™Æ™Ôd™‡–h7ÃAøAú áùõ=6?Eã½/ô|û ƒú7z:>„Çÿý<þ¯úýúßj?å¿þÇéöûþ“«ÿ¾ÁøKøÈ%ŠdOÿÞÈ<,Wþ‡ÿ·ƒïüúCÿß%Ï$sŸÿÃÿ÷‡þåiò>GÈù#ä|‘ò:#ä|Š":#¢:;ˆèŽˆèʤV‘ÑÑÑÑÑÑÑÑÑçIþ×o(¿zHDDDDDFp'.Ñ:ˆR:aAràÁ¬LˆÈù!ÿÿï[ÿ¯Äàiƒ"VƒDÇ)Ê6PáÈê$9C”9C†‡CD¡pE@¦œÖ{i~Úý¯kköDœ4ÉU”8`ƒt!l2G
--End Attach--

我尝试使用流式阅读器读取文件:

string[] lines = System.IO.File.ReadAllLines(@"C:\Users\Davide\Desktop\20041230000D.xmm")

我逐行读取文件,当行等于“Content-Transfer-Encoding: binary; Length=220096”时,我读取以下所有行并写入“文件名”(在本例中为 30085949.tif)文件. 但我正在读取字符串,而不是字节数据并且结果文件已损坏(现在我尝试使用 tiff 文件)。对我有什么建议吗?

解决方案 谢谢你的答复。我采用了这个解决方案:我构建了一个 LineReader 扩展 BinaryReader:

 public class LineReader : BinaryReader
    {
        public LineReader(Stream stream, Encoding encoding)
            : base(stream, encoding)
        {

        }

        public int currentPos;
        private StringBuilder stringBuffer;

        public string ReadLine()
        {
            currentPos = 0;

            char[] buf = new char[1];

            stringBuffer = new StringBuilder();
            bool lineEndFound = false;

            while (base.Read(buf, 0, 1) > 0)
            {
                currentPos++;
                if (buf[0] == Microsoft.VisualBasic.Strings.ChrW(10))
                {
                    lineEndFound = true;
                }
                else
                {                   
                    stringBuffer.Append(buf[0]);                    
                }
                if (lineEndFound)
                {
                    return stringBuffer.ToString();
                }

            }
            return stringBuffer.ToString();

        }

    }

其中 Microsoft.VisualBasic.Strings.ChrW(10) 是换行符。 当我解析我的文件时:

    using (LineReader b = new LineReader(File.OpenRead(path), Encoding.Default))
    {
        int pos = 0;
        int length = (int)b.BaseStream.Length;
        while (pos < length)
        {
            string line = b.ReadLine();
            pos += (b.currentPos);

            if (!beginNextPart)
            {
                if (line.StartsWith(BEGINATTACH))
                {
                    beginNextPart = true;

                }
            }
            else
            {
                if (line.StartsWith(ENDATTACH))
                {
                    beginNextPart = false;
                }
                else
                {
                    if (line.StartsWith("Content-Transfer-Encoding: binary; Length="))
                    {
                        attachLength = Convert.ToInt32(line.Replace("Content-Transfer-Encoding: binary; Length=", ""));
                        byte[] attachData = b.ReadBytes(attachLength);
                        pos += (attachLength);
                        ByteArrayToFile(@"C:\users\davide\desktop\files.tif", attachData);
                    }
                }
            }
        }
    }

我从文件中读取一个字节长度,然后读取以下 n 个字节。

【问题讨论】:

  • 您可以尝试手动读取文件内容,使用StreamReader 读取字符串,使用BinaryReader 读取二进制数据...
  • 看起来很实用——我只是希望你的底层流被缓冲(它可能是)或者你的性能会受到所有这些短读的影响。此外,'\n' 是 C#(以及所有类似 C 的语言)中表示与 Microsoft.VisualBasic.Strings.ChrW(10) 相同的值的惯用方式,并且还具有作为常量而不是函数调用的好处。
  • 感谢@MattW,'\n' 你的意思是我的比较变成了buf[0] == '\n'?我不明白缓冲区问题。请用一个例子解释一下。

标签: c# .net binary byte streamreader


【解决方案1】:

您的问题是 StreamReader 假定它是唯一读取文件的东西,因此它会提前读取。最好的办法是将文件读取为二进制文件并使用适当的文本编码从自己的缓冲区中检索字符串数据。

既然您显然不介意将整个文件读入内存,您可以从以下开始:

byte[] buf = System.IO.File.ReadAllBytes(@"C:\Users\Davide\Desktop\20041230000D.xmm");

然后假设您对文本数据使用 UTF-8:

int offset = 0;
int binaryLength = 0;
while (binaryLength == 0 && offset < buf.Length) {
    var eolIdx = Array.IndexOf(offset, 13); // In a UTF-8 stream, byte 13 always represents newline
    string line = System.Text.Encoding.UTF8.GetString(buf, offset, eolIdx - offset - 1);

    // Process your line appropriately here, and set binaryLength if you expect binary data to follow

    offset = eolIdx + 1;
}

// You don't necessarily need to copy binary data out, but just to show where it is:
var binary = new byte[binaryLength];
Buffer.BlockCopy(buf, offset, binary, 0, binaryLength);

如果您希望使用 Window 样式的行尾,您可能还想使用 line.TrimEnd('\r')。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-18
    • 2021-08-08
    • 2013-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-08
    • 2011-08-05
    相关资源
    最近更新 更多