添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
鼻子大的红酒  ·  Using the Jetty Maven ...·  5 月前    · 
开心的书包  ·  Blender 3.3 LTS 更新内容 ...·  6 月前    · 
俊秀的凳子  ·  SET LOCK_TIMEOUT ...·  7 月前    · 
狂野的卤蛋  ·  DatePicker ...·  1 年前    · 
听话的感冒药  ·  javascript - vue ...·  1 年前    · 

原始碼: Lib/csv.py

所謂的 CSV (Comma Separated Values) 檔案格式是試算表及資料庫中最常見的匯入、匯出檔案格式。在嘗試以 RFC 4180 中的標準化方式來描述格式之前,CSV 格式已經使用了許多年。由於缺少一個完善定義的標準,意味著各個不同的應用程式會在資料產生及銷毀時有微妙的差別。這些不同之處使得從不同資料來源處理 CSV 檔案時會非常擾人。儘管如此,雖然分隔符號和引號字元有所不同,整體的格式非常相似,可以寫個單一模組來高效率的操作這樣的資料,讓程式設計師可以隱藏讀取及寫入資料的細節。

csv 模組實作透過 class 去讀取、寫入 CSV 格式的表格資料。它讓程式設計師可以說出:「以 Excel 為首選並寫入該種格式的資料」或是「從 Excel 產生的檔案來讀取資料」,且無需知道這是 Excel 所使用的 CSV 格式等精確的細節。程式設計師也可以描述其他應用程式所理解的 CSV 格式或他們自行定義具有特殊意義的 CSV 格式。

csv 模組的 reader writer 物件可以讀取及寫入序列。程式設計師也可以透過 DictReader DictWriter class(類別)使用 dictionary (字典)讀取及寫入資料。

PEP 305 - CSV 檔案 API

Python Enhancement Proposal (PEP) 所提出的 Python 附加功能。

csv. reader ( csvfile , dialect = 'excel' , ** fmtparams )

回傳一個讀取器物件 (reader object) 並在指定的 csvfile 中逐行疊代 (iterate), csvfile 可以成為任何物件並支援 iterator 協定,每次呼叫 __next__() method(方法)時皆會回傳一個字串, 檔案物件 (file object) 及串列物件 (list object) 皆適用。如果 csvfile 是個檔案物件,則需開啟時使用 newline='' [ 1 ] dialect 為一個可選填的參數,可以用為特定的 CSV dialect(方言) 定義一組參數。它可能為 Dialect 的一個子類別 (subclass) 的實例或是由 list_dialects() 函式回傳的多個字串中的其中之一。另一個可選填的關鍵字引數 fmtparams 可以在這個 dialect 中覆寫 (override) 個別的格式化參數 (formatting parameter)。關於 dialect 及格式化參數的完整說明,請見段落 变种与格式参数

從 CSV 檔案讀取的每一列會回傳為一個字串列表。除非格式選項 QUOTE_NONNUMERIC 有被指定(在這個情況之下,沒有引號的欄位都會被轉換成浮點數),否則不會進行自動資料型別轉換。

一個簡短的用法範例:

>>> import csv
>>> with open('eggs.csv', newline='') as csvfile:
...     spamreader = csv.reader(csvfile, delimiter=' ', quotechar='|')
...     for row in spamreader:
...         print(', '.join(row))
Spam, Spam, Spam, Spam, Spam, Baked Beans
Spam, Lovely Spam, Wonderful Spam
csv.writer(csvfile, dialect='excel', **fmtparams)

回傳一個寫入器物件 (writer object),其負責在給定的類檔案物件 (file-like object) 上將使用者的資料轉換為分隔字串 (delimited string)。csvfile 可以為具有 write() method 的任何物件。若 csvfile 為一個檔案物件,它應該使用 newline='' 開啟 [1]dialect 為一個可選填的參數,可以用為特定的 CSV dialect 定義一組參數。它可能為 Dialect 的一個子類別的實例或是由 list_dialects() 函式回傳的多個字串中的其中之一。另一個可選填的關鍵字引數 fmtparams 可以在這個 dialect 中覆寫個別的格式化參數。關於 dialect 及格式化參數的完整說明,請見段落 变种与格式参数。為了更容易與有實作 DB API 的模組互相接合,None 值會被寫成空字串。雖然這不是一個可逆的變換,這使得dump (傾印) SQL NULL 資料值到 CSV 檔案上就無需讓 cursor.fetch* 呼叫回傳的資料進行預處理 (preprocessing)。其餘非字串的資料則會在寫入之前用 str() 函式進行字串化 (stringify)。

一個簡短的用法範例:

import csv
with open('eggs.csv', 'w', newline='') as csvfile:
    spamwriter = csv.writer(csvfile, delimiter=' ',
                            quotechar='|', quoting=csv.QUOTE_MINIMAL)
    spamwriter.writerow(['Spam'] * 5 + ['Baked Beans'])
    spamwriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
csv.field_size_limit([new_limit])

回傳當前的剖析器 (parser) 允許的最大字串大小。如果 new_limit 被給定,則會變成新的最大字串大小。

csv 模組定義了下列的類別:

class csv.DictReader(f, fieldnames=None, restkey=None, restval=None, dialect='excel', *args, **kwds)

建立一個物件,其運作上就像一般的讀取器,但可以將每一列資訊 map (對映) 到 dict 中,可以透過選填的參數 fieldnames 設定 key。

參數 fieldnames 是一個 sequence。如果 fieldnames 被省略了,檔案 f 中第一列的值會被當作欄位標題。不管欄位標題是如何決定的,dictionary都會保留原始的排序。

如果一列資料中的欄位比欄位標題還多,其餘的資料及以 restkey (預設為 None)特指的欄位標題會放入列表當中並儲存。如果一個非空的 (non-blank) 列中的欄位比欄位標題還少,缺少的值則會填入 restval (預設為 None)的值。

所有其他選填的引數或關鍵字引數皆會傳遞至下層的 reader 實例。

如果傳遞至 fieldnames 的引數是個疊代器,則會被迫成為一個 list

在 3.6 版的變更: 回傳的列已成為型別 OrderedDict

在 3.8 版的變更: 回傳的列已成為型別 dict

一個簡短的用法範例:

>>> import csv
>>> with open('names.csv', newline='') as csvfile:
...     reader = csv.DictReader(csvfile)
...     for row in reader:
...         print(row['first_name'], row['last_name'])
Eric Idle
John Cleese
>>> print(row)
{'first_name': 'John', 'last_name': 'Cleese'}
class csv.DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds)

建立一個物件,其運作上就像一般的寫入器,但可以將 dictionary map 到輸出的列上。參數 fieldnames 是一個鍵值的 sequence 且可以辨識 dictionary 中傳遞至 writerow() method 寫入至檔案 f 中的值。如果 dictionary 中缺少了 fieldnames 的鍵值,則會寫入選填的參數 restval 的值。如果傳遞至 writerow() method 的 dictionary 包含了一個 fieldnames 中不存在的鍵值,選填的參數 extrasaction 可以指出該執行的動作。如果它被設定為 'raise',預設會觸發 ValueError。如果它被設定為 'ignore',dictionary 中額外的值會被忽略。其他選填的引數或關鍵字引數皆會傳遞至下層的 writer 實例。

請記得這不像類別 DictReader,在類別 DictWriter 中,參數 fieldnames 並不是選填的。

如果傳遞至 fieldnames 的引數是個疊代器,則會被迫成為一個 list

一個簡短的用法範例:

import csv
with open('names.csv', 'w', newline='') as csvfile:
    fieldnames = ['first_name', 'last_name']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})
    writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'})
    writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})
class csv.Dialect

類別 Dialect 是一個容器類別,其屬性 (attribute) 包含如何處理雙引號、空白、分隔符號等資訊。由於缺少一個嚴謹的 CSV 技術規範,不同的應用程式會產出有巧妙不同的 CSV 資料。Dialect 實例定義了 reader 以及 writer 的實例該如何表示。

所有可用的 Dialect 名稱會透過 list_dialects() 回傳,且它們可以透過特定 readerwriter 類別的初始器 (initializer, __init__) 函式進行註冊,就像這樣:

import csv
with open('students.csv', 'w', newline='') as csvfile:
    writer = csv.writer(csvfile, dialect='unix')
                                 ^^^^^^^^^^^^^^
class csv.unix_dialect

類別 unix_dialect 定義了透過 UNIX 系統產生的 CSV 檔案的慣用屬性,換句話說,使用 '\n' 作為換行符號且所有欄位都被引號包覆起來。它被註冊的 dialect 名稱為 'unix'

在 3.2 版新加入.

has_header(sample)

分析 sample 文本(假定为 CSV 格式),如果发现其首行为一组列标题则返回 True。 在检查每一列时,将考虑是否满足两个关键标准之一来估计 sample 是否包含标题:

  • 第二至第 n 行包含数字值

  • 第二至第 n 行包含字符串值,其中至少有一个值的长度与该列预期标题的长度不同。

  • 会对第一行之后的二十行进行采样;如果有超过一半的列 + 行符合标准,则返回 True

    此方法是一个粗略的启发式方式,有可能产生错误的真值和假值。

    使用 Sniffer 的示例:

    with open('example.csv', newline='') as csvfile:
        dialect = csv.Sniffer().sniff(csvfile.read(1024))
        csvfile.seek(0)
        reader = csv.reader(csvfile, dialect)
        # ... process CSV file contents here ...
    

    csv 模块定义了以下常量:

    csv.QUOTE_ALL

    指示 writer 对象给所有字段加上引号。

    csv.QUOTE_NONE

    指示 writer 对象不使用引号引出字段。当 定界符 出现在输出数据中时,其前面应该有 转义符。如果未设置 转义符,则遇到任何需要转义的字符时,writer 都会抛出 Error 异常。

    指示 reader 对象不对引号字符执行特殊处理。

    csv.QUOTE_NOTNULL

    指示 writer 对象为所有不为 None 的字段加引号。 这类似于 QUOTE_ALL,区别是如果一个字段值为 None 则会写入一个(不带引号的)空字符串。

    指示 reader 对象将(不带引号的)空字段解读为 None 并在其他情况下采取与 QUOTE_ALL 相同的行为。

    csv.QUOTE_STRINGS

    指示 writer 对象总是为字符串字段加引号。 这类似于 QUOTE_NONNUMERIC,区别是如果一个字段值为 None 则会写入一个(不带引号的)空字符串。

    指示 reader 对象将(不带引号的)空字符串解读为 None 并在其他情况下采取与 QUOTE_NONNUMERIC 相同的行为。

    csv 模块定义了以下异常:

    exception csv.Error

    该异常可能由任何发生错误的函数抛出。

    变种与格式参数

    为了更容易指定输入和输出记录的格式,特定的一组格式参数组合为一个 dialect(变种)。一个 dialect 是一个 Dialect 类的子类,它具有一组特定的方法和一个 validate() 方法。创建 readerwriter 对象时,程序员可以将某个字符串或 Dialect 类的子类指定为 dialect 参数。要想补充或覆盖 dialect 参数,程序员还可以单独指定某些格式参数,这些参数的名称与下面 Dialect 类定义的属性相同。

    Dialect 类支持以下属性:

    Dialect.delimiter

    一个用于分隔字段的单字符,默认为 ','

    Dialect.doublequote

    控制出现在字段中的 引号字符 本身应如何被引出。当该属性为 True 时,双写引号字符。如果该属性为 False,则在 引号字符 的前面放置 转义符。默认值为 True

    在输出时,如果 doublequoteFalse,且 转义符 未指定,且在字段中发现 引号字符 时,会抛出 Error 异常。

    Dialect.escapechar

    一个用于 writer 的单字符,用来在 quoting 设置为 QUOTE_NONE 的情况下转义 定界符,在 doublequote 设置为 False 的情况下转义 引号字符。在读取时,escapechar 去除了其后所跟字符的任何特殊含义。该属性默认为 None,表示禁用转义。

    在 3.11 版的變更: 不允许空的 escapechar

    csvreader.__next__()

    返回 reader 的可迭代对象的下一行,它可以是一个列表(如果对象是由 reader() 返回)或字典(如果是一个 DictReader 实例),根据当前 Dialect 来解析。 通常你应当以 next(reader) 的形式来调用它。

    Reader 对象具有以下公开属性:

    csvreader.dialect

    变种描述,只读,供解析器使用。

    Writer 对象

    Writer 对象(DictWriter 实例和 writer() 函数返回的对象)具有下面的公开方法。对于 Writer 对象, 必须是(一组可迭代的)字符串或数字。对于 DictWriter 对象, 必须是一个字典,这个字典将字段名映射为字符串或数字(数字要先经过 str() 转换类型)。请注意,输出的复数会有括号包围。这样其他程序读取 CSV 文件时可能会有一些问题(假设它们完全支持复数)。

    csvwriter.writerow(row)

    row 形参写入到 writer 的文件对象,根据当前 Dialect 进行格式化。 返回对下层文件对象的 write 方法的调用的返回值。

    在 3.5 版的變更: 新增對任意 iterable 的支援。

    csvwriter.writerows(rows)

    rows*(即能迭代出多个上述 *row 对象的迭代器)中的所有元素写入 writer 的文件对象,并根据当前设置的变种进行格式化。

    Writer 对象具有以下公开属性:

    csvwriter.dialect

    变种描述,只读,供 writer 使用。

    DictWriter 对象具有以下公开方法:

    DictWriter.writeheader()

    在 writer 的文件对象中,写入一行字段名称(字段名称在构造函数中指定),并根据当前设置的变种进行格式化。本方法的返回值就是内部使用的 csvwriter.writerow() 方法的返回值。

    在 3.2 版新加入.

    在 3.8 版的變更: 现在 writeheader() 也返回其内部使用的 csvwriter.writerow() 方法的返回值。

    import csv
    with open('some.csv', newline='') as f:
        reader = csv.reader(f)
        for row in reader:
            print(row)
    

    读取其他格式的文件:

    import csv
    with open('passwd', newline='') as f:
        reader = csv.reader(f, delimiter=':', quoting=csv.QUOTE_NONE)
        for row in reader:
            print(row)
    

    相应最简单的写入示例是:

    import csv
    with open('some.csv', 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerows(someiterable)
    

    由于 open() 被用来打开 CSV 文件供读取,因此在默认情况下将使用系统默认编码格式 (参见 locale.getencoding()) 把文件解码至 unicode。 要使用其他编码格式来解码文件,请使用 open 的 encoding 参数:

    import csv
    with open('some.csv', newline='', encoding='utf-8') as f:
        reader = csv.reader(f)
        for row in reader:
            print(row)
    

    这同样适用于写入非系统默认编码的内容:打开输出文件时,指定 encoding 参数。

    注册一个新的变种:

    import csv
    csv.register_dialect('unixpwd', delimiter=':', quoting=csv.QUOTE_NONE)
    with open('passwd', newline='') as f:
        reader = csv.reader(f, 'unixpwd')
    

    Reader 的更高级用法——捕获并报告错误:

    import csv, sys
    filename = 'some.csv'
    with open(filename, newline='') as f:
        reader = csv.reader(f)
        try:
            for row in reader:
                print(row)
        except csv.Error as e:
            sys.exit('file {}, line {}: {}'.format(filename, reader.line_num, e))
    

    尽管该模块不直接支持解析字符串,但仍可如下轻松完成:

    import csv
    for row in csv.reader(['one,two,three']):
        print(row)
    [1]
    (1,2)
    

    如果没有指定 newline='',则嵌入引号中的换行符将无法正确解析,并且在写入时,使用 \r\n 换行的平台会有多余的 \r 写入。由于 csv 模块会执行自己的(通用)换行符处理,因此指定 newline='' 应该总是安全的。

    © 版權 2001-2023, Python Software Foundation. This page is licensed under the Python Software Foundation License Version 2. Examples, recipes, and other code in the documentation are additionally licensed under the Zero Clause BSD License. See History and License for more information.
    The Python Software Foundation is a non-profit corporation. Please donate. 最後更新於 9月 12, 2023。 Found a bug?