[英]reading stream from network using networkstream and streamreader
[英]Change StreamReader Encoding while reading from NetworkStream
我尝试从POP3中读取电子邮件,并在标题中找到字符集时更改为正确的编码。
我使用TCP客户端连接到POP3服务器。
下面是我的代码:
public string ReadToEnd(POP3Client pop3client, out System.Text.Encoding messageEncoding)
{
messageEncoding = TCPStream.CurrentEncoding;
if (EOF)
return ("");
System.Text.StringBuilder sb = new System.Text.StringBuilder(m_bytetotal * 2);
string st = "";
string tmp;
do
{
tmp = TCPStream.ReadLine();
if (tmp == ".")
EOF = true;
else
sb.Append(tmp + "\r\n");
//st += tmp + "\r\n";
m_byteread += tmp.Length + 2; // CRLF discarded by read
FireReceived();
if (tmp.ToLower().Contains("content-type:") && tmp.ToLower().Contains("charset="))
{
try
{
string charSetFound = tmp.Substring(tmp.IndexOf("charset=") + "charset=".Length).Replace("\"", "").Replace(";", "");
var realEnc = System.Text.Encoding.GetEncoding(charSetFound);
if (realEnc != TCPStream.CurrentEncoding)
{
TCPStream = new StreamReader(pop3client.m_tcpClient.GetStream(), realEnc);
}
}
catch { }
}
} while (!EOF);
messageEncoding = TCPStream.CurrentEncoding;
return (sb.ToString());
}
如果我删除此行:
TCPStream = new StreamReader(pop3client.m_tcpClient.GetStream(), realEnc);
一切工作正常,但是当电子邮件包含不同的字符集字符时,由于初始编码为ASCII,我会收到问号。
关于从网络流读取数据时如何更改编码的任何建议?
您做错了(tm)。
严重的是,您将尝试以完全错误的方式解决此问题。 不要为此使用StreamReader。 特别是不要一次读取1个字节(正如您所说,您需要在对较早的“解决方案”的评论中进行此操作)。
关于为何不使用StreamReader的解释,除了显而易见的“因为它并非旨在在读取过程中在编码之间切换”之外,还可以阅读我给出的关于在这里使用StreamReader的效率低下的另一个答案: 在C#中读取mbox文件
您需要做的就是缓冲读取的内容(例如4k缓冲区应该没问题)。 然后,因为您已经必须执行此操作,所以扫描'\\n'
字节以逐行提取内容,并合并折叠的标题行。
每个标头可能具有多个编码字令牌,假设它们已正确编码,则每个编码字令牌可能位于单独的字符集中,否则,您将不得不处理未声明的8位数据,并尝试以某种方式将其压缩为unicode(可能是通过后备字符集集)。 我建议先尝试UTF-8,然后再选择图书馆用户提供的一组字符集,然后再尝试iso-8859-1(确保在尝试了所有其他方法之前,不要尝试iso-8859-1,因为任何8位文本序列都可以使用iso-8859-1字符编码正确转换为unicode)。
当您获得消息的文本内容时,您将需要检查Content-Type
标头中的charset
参数。 如果未定义任何charset参数, 则应为US-ASCII,但实际上可以为任何值。 即使已定义字符集,它也可能与消息文本正文中使用的实际字符编码不匹配,因此,您可能再次想要一组备用。
正如您可能已经猜到的那样,这显然不是一项琐碎的任务,因为它要求解析器在进行过程中进行即时的字符转换(并且字符转换需要内部解析器状态以了解预期的字符集是什么)在任何给定时间)。
由于我已经完成了工作,因此您应该真正考虑使用MimeKit ,它将解析电子邮件,并使用适当的字符集编码对标头和内容进行字符集转换。
我还编写了包含在MailKit库中的Pop3Client类。
如果您的目标是学习和编写自己的库,我仍然强烈建议您阅读我的代码,因为它非常高效并且可以正确地执行操作。
有几种方法可以通过查看字节顺序标记来检测编码,这是流中少几个字节的地方。 这些将告诉您编码。 但是,该流可能没有BOM,在这种情况下,它可以是ASCII,不带BOM的UTF或其他。
您可以使用Encoding类将流从一种编码转换为另一种编码:
Encoding textEncoding = Encoding.[your detected encoding here];
byte[] converted = Encoding.UTF8.GetBytes(textEncoding.GetString(TCPStream.GetBuffer()));
您可以在转换时选择首选编码。
希望它能回答您的问题。
编辑
您可以使用此代码以块的形式读取流。
MemoryStream st = new MemoryStream();
int numOfBytes = 1024;
int reads = 1;
while (reads > 0)
{
byte[] bytes = new byte[numOfBytes];
reads = yourStream.Read(bytes, 0, numOfBytes);
if (reads > 0)
{
int writes = ( reads < numOfBytes ? reads : numOfBytes);
st.Write(bytes, 0, writes);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.