当前位置:  开发笔记 > 编程语言 > 正文

在C#中读取mbox文件

如何解决《在C#中读取mbox文件》经验,为你挑选了1个好方法。

我们的一名工作人员丢失了他的邮箱,但幸运的是他以mbox格式转发了他的电子邮件.我需要以某种方式获取mbox文件中的所有消息并将它们喷入我们的技术支持数据库(因为它是一个自定义工具,没有可用的导入工具).

我发现SharpMimeTools会分解消息但不允许您遍历mbox文件中的一堆消息.

有没有人知道一个不错的解析器打开而不必学习RFC写出一个?



1> jstedfast..:

我正在使用C#中的MIME和mbox解析器调用MimeKit.

它基于我编写的早期MIME和mbox解析器(例如GMime),它们非常快(可以在大约1秒内解析1.2GB mbox文件中的每条消息).

我还没有测试过MimeKit的性能,但是我在C#中使用了很多与C语言相同的技术.我怀疑它会比我的C实现慢,但是因为瓶颈是I/O而MimeKit是写得做最佳(4k)读取就像GMime一样,它们应该非常接近.

您发现当前方法变慢(StreamReader.ReadLine(),组合文本,然后将其传递给SharpMimeTools)的原因是由于以下原因:

    StreamReader.ReadLine()不是从文件中读取数据的最佳方式.虽然我确信StreamReader()执行内部缓冲,但它需要执行以下步骤:

    A)将从文件读取的字节块转换为unicode(这需要迭代从磁盘读取的byte []中的字节,以将从流中读取的字节转换为unicode char []).

    B)然后它需要遍历其内部char [],将每个char复制到StringBuilder中,直到找到'\n'.

    所以就在那里,只有阅读线,你的mbox输入流至少有2次传递.更不用说正在进行的所有内存分配......

    然后,将所有已阅读的行合并为一个单字符串.这需要对您的输入进行另一次传递(将从ReadLine()读取的每个字符串中的每个字符复制到StringBuilder中,大概是?).

    我们现在对输入文本进行了3次迭代,甚至还没有解析.

    现在你把你的超级字符串交给使用SharpMimeMessageStream的SharpMimeTools ......(/ facepalm)是一个基于ReadLine()的解析器,它位于另一个执行字符集转换的StreamReader之上.这甚至可以在任何事情之前进行5次迭代.SharpMimeMessageStream还有一种方法可以"撤消"ReadLine(),如果它发现它读得太远了.所以可以合理地假设他正在扫描其中一些线至少两次.更不用说所有正在进行的字符串分配......呃.

    对于每个标题,一旦SharpMimeTools具有其行缓冲区,它就会分为字段和值.那是另一个传球.到目前为止,我们最多可以通过6次.

    SharpMimeTools然后使用string.Split()(这是一个非常好的指示,这个mime解析器不符合标准)通过拆分','和参数化标题(如Content-Type和Content-Disposition)来分割地址标题上 ';'.那是另一个传球.(我们现在最多7次通过.)

    一旦它拆分,它就会在string.Split()返回的每个字符串上运行正则表达式匹配,然后在最终对编码字字符集和有效负载组件进行另一次传递之前,每个rfc2047编码字令牌传递更多正则表达式.到目前为止,我们正在谈论大部分输入中至少9或10次传球.

我放弃了我的检查,因为它已经超过GMime和MimeKit需要的2倍,我知道我的解析器可以优化至少比他们少一次.

另外,作为旁注,任何解析字符串而不是byte [](或sbyte [])的MIME解析器永远不会很好.电子邮件的问题在于,野外的许多邮件客户端/脚本/等将在标头和邮件正文中发送未声明的8位文本.如何才能unicode字符串解析器可能处理这个问题?提示:它不能.

2013-09-18更新:我已经获得了MimeKit,它现在可用于解析mbox文件并成功设法解决问题,但它并不像我的C库那么快.这是在iMac上测试的,因此I/O性能不如我在旧的Linux机器上那么好(这是GMime能够在~1s内解析类似大小的mbox文件):

[fejj@localhost MimeKit]$ mono ./mbox-parser.exe larger.mbox 
Parsed 14896 messages in 6.16 seconds.
[fejj@localhost MimeKit]$ ./gmime-mbox-parser larger.mbox 
Parsed 14896 messages in 3.78 seconds.
[fejj@localhost MimeKit]$ ls -l larger.mbox 
-rw-r--r--  1 fejj  staff  1032555628 Sep 18 12:43 larger.mbox

正如您所看到的,GMime仍然相当快,但我对如何提高MimeKit解析器的性能有一些想法.事实证明,C#的fixed陈述非常昂贵,所以我需要重新使用它们.例如,我昨天做的一个简单的优化在整个时间内削减了大约2-3秒(如果我没记错的话).

优化更新:通过替换以下内容,将性能提高了20%:

while (*inptr != (byte) '\n')
    inptr++;

有:

do {
    mask = *dword++ ^ 0x0A0A0A0A;
    mask = ((mask - 0x01010101) & (~mask & 0x80808080));
} while (mask == 0);

inptr = (byte*) (dword - 1);
while (*inptr != (byte) '\n')
    inptr++;

优化更新:通过改变我对Enum.HasFlag()的使用并使用直接位掩码,我终于能够像GMime一样快速制作MimeKit.

MimeKit现在可以在3.78秒内解析相同的mbox流.

相比之下,SharpMimeTools需要20多分钟(为了测试这一点,我不得不将电子邮件分成单独的文件,因为SharpMimeTools无法解析mbox文件).

另一个更新:我已经通过代码中的各种其他调整将它降低到3.00s.

推荐阅读
mobiledu2402852357
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有