【问题标题】:Determine if a file is "more likely" json or csv确定文件“更可能”是 json 还是 csv
【发布时间】:2019-07-08 22:27:51
【问题描述】:

我有一些具有通用扩展名的文件,例如“txt”或根本没有扩展名。我试图以非常快速的方式确定文件是 json 还是 csv。我想过使用 magic 模块,但它不适用于我想要做的事情。例如:

>>> import magic
>>> magic.from_file('my_json_file.txt')
'ASCII text, with very long lines, with no line terminators'

有没有更好的方法来确定是 json 还是 csv?我无法加载整个文件,我想以非常快速的方式确定它。这里有什么好的解决方案?

【问题讨论】:

  • 即使有办法根据文件的内容找出文件的类型,但如果文件内的JSON无效或分隔符在 csv 数据和其他此类问题中不一致。此外,txt 文件中的所有内容都被视为string 类型,无论是否为 JSON。
  • @amanb 如果它无效也没关系。我只是想看看——基于文件中的前 1000 个字符是“可能是 json 或可能是 csv”。现在做类似s.startswith('{') 的事情比magic 给了我更好的结果,所以必须有一些更准确的东西......
  • 嗯,您无法加载整个文件,但 magic.from_file 可以说没有行终止符。显然它可以加载整个文件。
  • Helpful semi-related post 供日后参考
  • @RemcoGerlich 我刚刚将一些数据复制粘贴到该文件中以进行测试。这些文件可能非常大(10GB),我只下载前 1KB 左右,以查看它可能是哪种文件类型,没有明确的扩展名。

标签: python python-3.x mime


【解决方案1】:

您可以使用try/catch“技术”尝试将数据解析为 JSON 对象。从字符串加载无效格式的 JSON 时,它会引发 ValueError,您可以根据需要捕获和处理它:

>>> import json
>>> s1 = '{"test": 123, "a": [{"b": 32}]}'
>>> json.loads(s1)

如果有效,则什么也不会发生,否则:

>>> import json
>>> s2 = '1;2;3;4'
>>> json.loads(s2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 338, in loads
    return _default_decoder.decode(s)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/decoder.py", line 369, in decode
    raise ValueError(errmsg("Extra data", s, end, len(s)))
ValueError: Extra data: line 1 column 2 - line 1 column 8 (char 1 - 7)

所以你可以如下构建一个函数:

import json

def check_format(filedata):
    try:
        json.loads(filedata)
        return 'JSON'
    except ValueError:
        return 'CSV'

>>> check_format('{"test": 123, "a": [{"b": 32}]}')
'JSON'
>>> check_format('1;2;3;4')
'CSV'

【讨论】:

  • 为此你需要阅读整个文件,而他不能。
【解决方案2】:

您可以检查文件是否以{[ 开头以确定它是否为JSON,您可以使用csv.reader 加载前两行并查看这两行是否具有相同的列数确定它是否为 CSV。

import csv
with open('file') as f:
    if f.read(1) in '{[':
        print('likely JSON')
    else:
        f.seek(0)
        reader = csv.reader(f)
        try:
            if len(next(reader)) == len(next(reader)) > 1:
                print('likely CSV')
        except StopIteration:
            pass

【讨论】:

  • 简单的方法,我喜欢这个。感谢您提供此解决方案。
  • 关于这个的一个问题——你为什么不想在rb 模式下打开文件?例如,如果它不是 utf-8 编码(假设它是 utf-16 编码)怎么办?
  • CSV 中的所有行不需要具有相同的列数。事实上,在标题之后和数据开头之前留下一个完全空白的行并非闻所未闻。
  • 漂亮的解决方案!.. 有一天我可能会将它用于我自己的目的。
  • 但是如果是单行10GB的JSON文件,那就有问题了。
猜你喜欢
  • 2021-05-07
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-04
  • 1970-01-01
  • 2012-05-31
  • 2010-12-28
相关资源
最近更新 更多