【问题标题】:How to find out how many characters a file has without reading the whole of it?如何在不阅读整个文件的情况下找出文件有多少个字符?
【发布时间】:2011-05-23 19:36:41
【问题描述】:

如果文件是文本文件,而StreamReader 可以算出它使用的Encoding,我如何在不读取整个文件的情况下知道它有多少字符?

我正在读取 1GB 的 CSV 文件,使用 StreamReader 读取它至少需要 4 秒。 File.ReadAllText().Length 会导致 System.OutOfMemoryException

我想如果我有FileInfo(filename).LengthEncoding,那么我可以计算字符数。

【问题讨论】:

  • 这取决于编码的类型,length 会给你字节数,在 ASCII 中是字符数,但对于 UTF/Unicode,你在解码之前无法知道。

标签: c# .net file character-encoding streamreader


【解决方案1】:

你不能。原因是,一些编码(特别是 UTF-8)具有可变字符宽度:一些字符只占用 1 个字节(ASCII),很多占用 2 个字节,甚至每个字符有 3 个或更多字节的情况。因此,如果不对字符进行解码,就不可能知道编码下文件的长度。

此外,C# 字符串中的所有字符都表示为 UTF-16、AFAIK,因此除非您有非常奇怪的文本(即您使用来自外部 plane 0 的许多字符),否则您可以以字节为单位估算内存需求相当容易,通过将字符数乘以 2(反之亦然,通过将字节大小加倍来估计字符数)。

现在,一个更好的问题是 - 为什么需要字符数?您稍后对 CSV 文件做了什么,您想将其全部加载到内存中,为什么知道它的大小会有所帮助?

【讨论】:

  • +1。但是,应该可以编写一个方法来计算文件中的 UTF-8 编码字符,这比使用 Encoding.UTF8 的 StreamReader 读取字符要快。
  • 那么估计呢?文件的第一行可以让我估计文件其余部分的字符数?
  • @dtb 我打赌你不能,相信我我试过stackoverflow.com/questions/6101367/how-to-count-lines-fast/…
  • @Jader Dias:如果您只需要估算并且您的文件不包含太多非 ASCII 字符,则可以使用 FileInfo.Length。
  • @Chris Haas:不,不是全部。例如,UTF-16 对所有字符(包括 U+0000 到 U+007F 范围内的字符)使用两个字节(在代理对的情况下使用四个字节)。 UTF-32 对所有字符使用四个字节。
【解决方案2】:

对于 ASCII、CP-437、CP-1252、ISO-8859-1 或类似的代码页,则字符数将是字节数。

如果文件是UTF-16,那么你无法从字节数知道字符数,但很可能类似于字节数/2。无论如何,你都可以准确地计算出将文件保存在 .NET 字符串中所需的内存大小,因为它将是文件的大小(因为 .NET 在内部使用 UTF-16)加上恒定开销。这样一个字符串的长度将是字节数除以 2。

如果文件采用 UTF-8(或任何其他可变宽度编码),则字符数可以是很宽的范围,最高可达字节数的几倍,或者每个字节一个字符。这取决于数据。

如果文件是 UTF-32 格式(这极不可能),那么字符数将正好是文件长度除以 4 的字节数。但即使这是确切的字符数,它并不表示从此文件创建的 .NET 字符串的长度,因为这可能涉及对高平面字符使用代理代码点,所以答案仍然取决于您打算如何处理这些信息。

【讨论】:

  • 那么如何检测文件编码呢?
  • @Jader Dias - 除非文件以字节顺序标记开头,否则没有可靠的方法来检测编码。有一些启发式方法可以用来猜测,但这是另一个大问题。 (而“文件中有多少个字符?”如果您不知道文件的编码,这是一个毫无意义的问题。如果您无法正确读取文件,即使读取文件也不会告诉您。)
  • 但我敢打赌StreamReader 使用编码检测,即使它不可靠。
  • @Jader Dias - 如果你相信它,那就使用它。 StreamReader 有一个 CurrentEncoding 属性。它不需要您阅读整个文件。
【解决方案3】:

我不认为它真的可以 - 某些编码对具有不同字节数的字符进行编码,因此您确实需要将字节转换为字符才能找到字符数。

例如,在 UTF-8 中,从 \u0000 到 \u007F 的字符仅用 1 个字节表示;在 \0u0080 和 \u07FF 之间,它们需要 2 个字节,依此类推。

【讨论】:

  • 那么估计呢?文件的第一行可以让我估计文件其余部分的字符数?
  • 只要你对这个估计感到满意,那就去做吧。如果您从 100 个字节中得到 90 个字符,那么您可以估计 90% 的字节将是字符。您使用的样本数据越多,您的估计就会越好。
【解决方案4】:

这适用于某些编码(ASCII、Window 1262、IBM-850 等),但不适用于 UTF8 和 UTF7,因为它们有一些编码为 1 字节的字符,一些编码为 2(我相信还有一些编码为 2 )。

【讨论】:

  • 以及如何估计字符数?我可以知道文件前 100 行的字节和字符大小,然后计算文件的大致字符数吗?该怎么做?
  • 取决于内容。假设您有一个带有英文文本的 UTF-8 文件,然后是日文翻译。英语通常每个字符占用 1 个字节,日语每个字符占用 2 个字节。如果你按文件顶部进行估计,你会得到非常错误的结果。
  • @Jader Dias,它是预先确定缓冲区大小和最小化重新分配的好方法。您可以花哨并保持运行估算以改善调整大小。
  • @Amadan 这不是我的情况,我有一个非常常规的 CSV 文件
  • 我不知道什么对你来说很正常。我住在日本,所以我的情况对我来说并不是太不可思议:)
【解决方案5】:

问题在于,如果文件是 UTF8 编码的,那么每个字符可以占用 1 到 4 个字节,因此如果不以某种方式处理文件,就无法“计算”字符数。

其他编码方法可能会更有成效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-09
    • 1970-01-01
    • 2016-08-14
    • 2011-05-15
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多