F#中CSVProvider是否支持读取gzip压缩的URL端TSV文件?
类型提供程序“ProviderImplementation.CsvProvider”报告错误:无法从“https://datasets.imdbws.com/name.basics.tsv.gz”读取CSV样本:无法根据架构解析第1行:预期2列,实际得到1列。
这个报错的核心原因是F#的CsvProvider默认不会自动处理gzip压缩的数据流,你直接传入gzip格式的URL时,类型提供程序读取到的是压缩后的二进制乱码,而非纯文本格式的TSV内容,所以解析列数完全不符合预期。
CsvProvider本身是编译时生成类型的机制,只要配合少量自定义解压代码,就可以实现压缩CSV/TSV的便捷分析,不需要完全手动写解析逻辑,具体实现可以参考如下步骤:
1. 编译阶段生成类型
你可以先手动把对应的gz压缩包下载到本地,解压得到纯文本TSV样本文件,用本地样本生成对应的类型:
// 注意替换为你本地解压后的TSV文件路径,分隔符显式指定为制表符 type NameBasics = CsvProvider<"./name.basics.tsv", Separators="\t">
如果你不想保留本地样本文件,也可以提前截取解压后TSV的表头加前几行数据作为静态字符串,传给Sample参数生成类型:
let sample = """nconst primaryName birthYear deathYear primaryProfession knownForTitles nm0000001 Fred Astaire 1899 1987 soundtrack,actor,miscellaneous tt0050419,tt0031983,tt0072308,tt0043044 nm0000002 Lauren Bacall 1924 2014 actress,soundtrack tt0071877,tt0038355,tt0037382,tt0117057""" type NameBasics = CsvProvider<Sample=sample, Separators="\t">
2. 运行阶段加载远程压缩数据
运行时你只需要自己实现gzip流的解压逻辑,把解压后的纯文本流传给Load方法即可,完整示例代码:
open System open System.IO open System.IO.Compression open System.Net.Http open FSharp.Data let loadRemoteImdbNameBasics () = task { use client = new HttpClient() use! compressedStream = client.GetStreamAsync("https://datasets.imdbws.com/name.basics.tsv.gz") use decompressStream = new GZipStream(compressedStream, CompressionMode.Decompress) use reader = new StreamReader(decompressStream) return NameBasics.Load(reader) }
调用这个方法拿到的数据集,和直接读取本地纯文本TSV得到的结构完全一致,你可以直接用自动生成的强类型字段访问每一列数据。
F#的CSV类型提供程序本身没有内置gzip自动处理能力,但只要补充几十行的解压逻辑,就可以完全保留类型提供程序的便捷性,不需要手动处理TSV的列解析、类型转换等逻辑,完全可以满足压缩CSV/TSV的分析需求。
内容的提问来源于stack exchange,提问作者Gabriel Guillermo

