使用pd.read_parquet读取FTP服务器Parquet文件时触发FileNotFoundError
Pandas读取FTP上Parquet文件失败,但读取CSV正常
问题详情
尝试用Pandas的read_parquet方法读取FTP服务器上的二进制Parquet文件,代码如下:
import pandas as pd df = pd.read_parquet('ftp://ftp.hostname.com/binary/filename.parquet', engine='fastparquet')
触发错误:
FileNotFoundError: ftp://ftp.hostname.com/binary/filename.parquet
已确认文件路径正确,且读取同一FTP服务器上的CSV文件无异常:
pd.read_csv('ftp://ftp.hostname.com/csv/filename.csv')
更换engine='pyarrow'后问题依旧。将文件下载到本地后,使用pd.read_parquet可正常读取;通过urllib也能成功获取文件内容:
import urllib.request urllib.request.urlretrieve('ftp://ftp.hostname.com/binary/filename.parquet', 'file')
或:
from urllib import request req = request.urlopen('ftp://ftp.hostname.com/binary/filename.parquet') df = req.read()
得到结果df = '\x00\x11...',不确定是否为文件编码问题。
补充报错栈
read_parquet完整报错栈:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "...\Python312\Lib\site-packages\pandas\io\parquet.py", line 670, in read_parquet return impl.read( ^^^^^^^^^^ File "...\Python312\Lib\site-packages\pandas\io\parquet.py", line 400, in read parquet_file = self.api.ParquetFile(path, **parquet_kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "...\Python312\Lib\site-packages\fastparquet\api.py", line 178, in __init__ raise FileNotFoundError(fn) FileNotFoundError: ftp://ftp.hostname.com/binary/filename.parquet
尝试用read_csv读取该Parquet文件的报错栈:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "...\Python312\Lib\site-packages\pandas\io\parsers\readers.py", line 948, in read_csv return _read(filepath_or_buffer, kwds) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "...\Python312\Lib\site-packages\pandas\io\parsers\readers.py", line 611, in _read parser = TextFileReader(filepath_or_buffer, **kwds) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "...\Python312\Lib\site-packages\pandas\io\parsers\readers.py", line 1448, in __init__ self._engine = self._make_engine(f, self.engine) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "...\Python312\Lib\site-packages\pandas\io\parsers\readers.py", line 1723, in _make_engine return mapping[engine](f, **self.options) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "...\Python312\Lib\site-packages\pandas\io\parsers\c_parser_wrapper.py", line 93, in __init__ self._reader = parsers.TextReader(src, **kwds) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "parsers.pyx", line 579, in pandas._libs.parsers.TextReader.__cinit__ File "parsers.pyx", line 668, in pandas._libs.parsers.TextReader._get_header File "parsers.pyx", line 879, in pandas._libs.parsers.TextReader._tokenize_rows File "parsers.pyx", line 890, in pandas._libs.parsers.TextReader._check_tokenize_status File "parsers.pyx", line 2050, in pandas._libs.parsers.raise_parser_error File "<frozen codecs>", line 322, in decode UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 7-8: invalid continuation byte
解决方案
原因分析
Pandas的read_parquet底层依赖的fastparquet和pyarrow库,不直接支持FTP URL作为输入路径,而read_csv因为Pandas本身做了URL资源的封装处理,所以能正常读取FTP上的CSV文件。
可行解决方法
方法1:内存中读取(无需本地文件)
利用BytesIO将下载的二进制内容直接传入read_parquet:
import pandas as pd from urllib import request from io import BytesIO # 获取FTP上的Parquet文件二进制内容 req = request.urlopen('ftp://ftp.hostname.com/binary/filename.parquet') parquet_content = req.read() # 用BytesIO包装后读取 df = pd.read_parquet(BytesIO(parquet_content), engine='fastparquet')
方法2:用fsspec扩展远程文件系统支持
fsspec可以让Parquet引擎支持FTP等远程文件系统,先安装依赖:
pip install fsspec ftputil
然后修改代码:
import pandas as pd import fsspec # 建立FTP文件系统连接 fs = fsspec.filesystem('ftp', host='ftp.hostname.com') # 打开文件并读取 with fs.open('/binary/filename.parquet', 'rb') as f: df = pd.read_parquet(f, engine='fastparquet')
注意事项
用read_csv读取Parquet文件出现的UnicodeDecodeError是正常现象——Parquet是二进制格式,和文本CSV的编码、格式完全不同,不能混用读取方法。
内容的提问来源于stack exchange,提问作者Kimi
相关产品推荐
相关产品推荐

