【问题标题】:How to check if a file is a CSV, XML, or JSON without relying on the file extension?如何在不依赖文件扩展名的情况下检查文件是 CSV、XML 还是 JSON?
【发布时间】:2022-01-18 08:35:56
【问题描述】:

我有一个程序可以接受多个输入文件的组合,也可以使用目录来扫描这些输入文件。

通常,我只接受具有 CSV、XML 和 JSON 的有效文件扩展名的文件 - 但正如我多年来了解到的那样,你不能真正相信用户提供正确的文件。

例如,如果用户有一个带有 XML 扩展名的文件,但实际内容是 JSON,我想警告用户并将该文件视为 JSON 文件。 另一种情况是在基于 Unix 的操作系统上,文件扩展名不像 Windows 那样用于识别文件类型,与文件内容相比,这可能会导致更多文件类型不正确的情况。

现在,我的程序收集文件列表,将它们过滤为仅具有可接受文件扩展名的文件,然后我创建一个concurrent.futures.ThreadPoolExecutor 以便能够同时检查所有文件。实际检查如下:

with open(the_file, "r") as f:
  check = f.read(1)
  if check == "{" or check == "[":
    file_type = "json"
  elif check == "<":
    file_type = "xml"
  else:
    file_type = "csv"

这有两个主要问题:

  1. 如果文件应该是 CSV,并且它的第一个字符是 [{&lt;,那么程序将为其分配错误的文件类型。
  2. 相反,如果文件不是任何可接受的类型,并且它不是以[{&lt; 开头,那么程序将假设该文件应该是一个CSV .

我有以下想法来解决这个问题:

import csv
import json
import defusedxml.ElementTree as xml

try:
  loaded = xml.parse(the_file)
  return "XML"
except xml.ParseError:
  del loaded
  try:
    loaded = json.load(the_file)
    return "JSON"
  except json.JSONDecodeError:
    del loaded
    try:
      with open(the_file, "r") as csv_file:
        loaded = csv.DictReader(csv_file)
      return "CSV"
    except csv.Error:
      print("The file is not in any acceptable format")

问题在于,由于我的程序尝试同时对多个文件运行此检查,因此同时打开这么多文件时,内存使用率可能会变得非常高。另一个小问题是一次打开和关闭这么多文件以检查文件类型的 I/O 成本。

对于我正在尝试做的事情,是否有更有效的替代方法?

【问题讨论】:

  • 对于xml文件,你可以试试正则表达式,看看这个文件的第一行是否包含&lt;?xml version="1.0" encoding="ISO-8859-1"?&gt;之类的东西。
  • 并非所有 XML 文件实际上都需要以 &lt;?xml version 开头,它们也不必包含编码类型。为这些东西添加正则表达式可以作为检查 XML 文件的补充,但是当不能完全保证判断文件是否是有效的 XML 文件时,我不会仅仅依赖它。
  • 不会尝试使用正则表达式,不妨尝试解析它,否则您不知道这是一个有效的 XML 或 JSON 文件。
  • 如果资源/时间不是问题,我会尝试对每种格式进行解析,然后继续使用不会产生解析错误的格式。
  • @Hunter_AP 你说得对,确实,这个问题基本上没有好的解决办法,总会有一些极端的情况。

标签: python python-3.x file


【解决方案1】:

这里只是一些极端案例,以表明您不能既只阅读某些字符又希望得到可靠的分类:

以 json 开头,但实际上是带有分号分隔符的 csv:

[12];[13,14]
...

以 xml 开头,但又是 csv

<foo>,<bar>,<fee>
1,2,3
...

以空格开头,但它是一个有效的 xml(空格在此处记为 _):

__<foo>text...</foo>

恕我直言,你能做的最好的就是读取文件的第一个字符来决定首先测试什么格式,但是:

  • 您必须至少阅读每个文件一次
  • 您将不得不多次阅读极端案例或不正确的文件

【讨论】:

    【解决方案2】:

    XML JSON 和 CSV 的呈现方式不同,可以通过第一行来区分。
    例如 JSON 可能会以 {[{ 开头。
    例如,XML 应以 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
    开头 CSV 有点棘手,因为第一行可以有更多种类的输入,但根据预期的数据,您可以自定义其他测试。

    这种方法显然不会验证实际数据,但可以帮助检测您正在处理的格式。

    【讨论】:

    • 是的,这就是问题所在,CSV 文件可以以 JSON 和 XML 文件的任何字符开头。也不是所有的 XML 文件都以&lt;?xml version="1.0" encoding="UTF-8"?&gt; 开头,因为第一个标签实际上可以是用户或编写 XML 文件的任何程序想要的任何关键字。这就是为什么在我的情况下,我专门寻找 &lt; 字符。
    • 这部分只是 not true:“例如 JSON 必须以 { 或 [{。” 参见规范:json.org跨度>
    • @djvg 是的,你说得对,我将这一行编辑为“可能”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-31
    • 1970-01-01
    • 2015-06-30
    • 2015-12-08
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    相关资源
    最近更新 更多