Python中将dbf转换为csv的方法是什么?

4

我有一个文件夹,里面有大量dbf文件,我想将它们转换成csv格式。我尝试过使用一段代码来仅仅更改扩展名从.dbf到.csv,这些文件在Excel中打开时没有问题,但是当我在pandas中打开它们时,它们看起来像这样:

                                                s\t�
0                                                NaN
1            1       176 1.58400000000e+005-3.385...

这不是我想要的,而且那些字符在真实文件中并不存在。
我该如何正确读入dbf文件?

5个回答

6

这是我多年来一直在使用的解决方案。我有一个针对Python 2.7的解决方案,还有一个针对Python 3.5(可能也适用于3.6)。

Python 2.7:

import csv
from dbfpy import dbf

def dbf_to_csv(out_table):#Input a dbf, output a csv
    csv_fn = out_table[:-4]+ ".csv" #Set the table as .csv format
    with open(csv_fn,'wb') as csvfile: #Create a csv file and write contents from dbf
        in_db = dbf.Dbf(out_table)
        out_csv = csv.writer(csvfile)
        names = []
        for field in in_db.header.fields: #Write headers
            names.append(field.name)
        out_csv.writerow(names)
        for rec in in_db: #Write records
            out_csv.writerow(rec.fieldData)
        in_db.close()
    return csv_fn

Python 3.5:

import csv
from dbfread import DBF

def dbf_to_csv(dbf_table_pth):#Input a dbf, output a csv, same name, same path, except extension
    csv_fn = dbf_table_pth[:-4]+ ".csv" #Set the csv file name
    table = DBF(dbf_table_pth)# table variable is a DBF object
    with open(csv_fn, 'w', newline = '') as f:# create a csv file, fill it with dbf content
        writer = csv.writer(f)
        writer.writerow(table.field_names)# write the column name
        for record in table:# write the rows
            writer.writerow(list(record.values()))
    return csv_fn# return the csv name

你可以通过pip install获取dbfpy和dbfread。


4
使用 我的 dbf 库,你可以做如下操作:
import sys
import dbf
for arg in sys.argv[1:]:
    dbf.export(arg)

这将创建一个与每个dbf文件同名的.csv文件。如果您将该代码放入名为dbf2csv.py的脚本中,则可以通过以下方式调用它:

python dbf2csv.py dbfname dbf2name dbf3name ...

伊桑,你的库有没有文档? - N4v
@N4v:不完全是。虽然在Stackoverflow上有很多有趣的东西。 - Ethan Furman

3

在网上搜索,有几个选项:


使用 simpledbf

dbf = Dbf5('fake_file_name.dbf')
df = dbf.to_dataframe()

这是从Gist调整过来的:

import pysal as ps

def dbf2DF(dbfile, upper=True):
    "Read dbf file and return pandas DataFrame"
    with ps.open(dbfile) as db:  # I suspect just using open will work too
        df = pd.DataFrame({col: db.by_col(col) for col in db.header})
        if upper == True: 
           df.columns = map(str.upper, db.header) 
        return df

我从仅有几行脚本中调用了你的函数dbf2DF。调用open时出现了以下错误:AttributeError: __exit__。 - Dobedani
奇怪。__exit__ 在 with 块中是必需的,也许由于某种原因它们被弃用了?尝试使用 db = ps.open(dbfile) 和 dedent。 - Andy Hayden
没有 "with" 关键字,代码确实可以正常工作。谢谢! - Dobedani

1

首先,您应该知道Dbf版本,因此请阅读文件的第一个字节:

path = "/path/to/dbf/file.dbf"
with open(path, "rb") as f:
     byte = f.read(1)
     print(f"You have a DBF {int.from_bytes(byte)} file.")

示例:

> 你有一个DBF 3文件。

如果你有一个Dbf 5文件,那么一切都会很好,但是,大多数情况下,就像我的情况一样,你有一个Dbf 3文件,那么你需要使用simpledbf对@andy-hayden解决方案进行微调:

根据问题,基本上你应该创建一个继承自Dbf5的类Dbf3,但是你需要向_get_recs方法添加一个新的条件。

import struct

from simpledbf import Dbf5

class Dbf3(Dbf5):
   def __init__(self, dbf, codec='utf-8'):
       super().__init__(dbf, codec)
   
   def _get_recs(self, chunk=None):
#[...copy the code from the original class up until line 664...]
               elif typ == 'M':
                   value = self._na
#[...copy the code from the original class after 664...]

参考原始Dbf代码

然后你的新类Dbf3将能够轻松读取和转换Dbf3文件:

dbf = Dbf3(filename, codec="iso-8859-1") #codec specific to this dataset 
dbf.to_csv("converted_dbf.csv")

1

编辑#2:

可以使用dbfread按行读取dbf文件,无需将其转换为csv(只需使用pip install dbfread进行安装):

>>> from dbfread import DBF
>>> for row in DBF('southamerica_adm0.dbf'):
...     print row
... 
OrderedDict([(u'COUNTRY', u'ARGENTINA')])
OrderedDict([(u'COUNTRY', u'BOLIVIA')])
OrderedDict([(u'COUNTRY', u'BRASIL')])
OrderedDict([(u'COUNTRY', u'CHILE')])
OrderedDict([(u'COUNTRY', u'COLOMBIA')])
OrderedDict([(u'COUNTRY', u'ECUADOR')])
OrderedDict([(u'COUNTRY', u'GUYANA')])
OrderedDict([(u'COUNTRY', u'GUYANE')])
OrderedDict([(u'COUNTRY', u'PARAGUAY')])
OrderedDict([(u'COUNTRY', u'PERU')])
OrderedDict([(u'COUNTRY', u'SURINAME')])
OrderedDict([(u'COUNTRY', u'U.K.')])
OrderedDict([(u'COUNTRY', u'URUGUAY')])
OrderedDict([(u'COUNTRY', u'VENEZUELA')])

我的更新参考资料:

官方项目网站:http://pandas.pydata.org

官方文档:http://pandas-docs.github.io/pandas-docs-travis/

dbfread: https://pypi.python.org/pypi/dbfread/2.0.6

geopandas: http://geopandas.org/

使用geopandas读取shp和dbf文件https://gis.stackexchange.com/questions/129414/only-read-specific-attribute-columns-of-a-shapefile-with-geopandas-fiona


是的,我已经在“文档”一词下添加了文档链接,现在我已经明确报告了它。 - Alessandro Trinca Tornidor
请注意,那并不是官方的pandas文档网站,我认为PANDA是完全不同的东西(但我不清楚是什么)。 - Andy Hayden
我现在注意到我的解决方案并不是最优的。更好的选择是dbfread - Alessandro Trinca Tornidor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接