深入理解Python CSV文件讀取與csv.reader函數(shù)使用指南
在數(shù)據(jù)科學(xué)、自動化腳本開發(fā)以及日常辦公任務(wù)中,CSV(Comma-Separated Values)文件是一種極為常見的數(shù)據(jù)格式。它以純文本形式存儲表格數(shù)據(jù),每一行代表一條記錄,字段之間用逗號分隔。由于其簡單、通用且易于解析的特性,幾乎所有的編程語言都提供了對CSV文件的支持。
而在眾多語言中,Python憑借其簡潔的語法和強大的標(biāo)準(zhǔn)庫,成為了處理這類任務(wù)的首選工具之一。特別是內(nèi)置的 csv 模塊,為開發(fā)者提供了一套高效、安全且靈活的方式來讀取和寫入CSV文件。今天,我們就來深入探討這個模塊的核心函數(shù)——csv.reader(),并結(jié)合真實代碼示例、可視化圖表和實際應(yīng)用場景,帶你從入門到精通。
什么是csv.reader()?
csv.reader() 是 Python csv 模塊中的一個核心函數(shù),用于將一個可迭代對象(如文件對象)中的內(nèi)容按行解析為列表形式的行數(shù)據(jù)。它的作用是“把原始的字符串行”轉(zhuǎn)化為“結(jié)構(gòu)化的數(shù)據(jù)行”。
基本語法
import csv
with open('data.csv', 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
print(row)
這里的 reader 是一個迭代器對象,每次調(diào)用 next(reader) 或在 for 循環(huán)中遍歷時,都會返回一行數(shù)據(jù)(以列表形式表示)。
提示:csv.reader() 不會自動識別列名或表頭,它只是逐行讀取原始內(nèi)容。如果需要處理標(biāo)題行,通常需手動跳過第一行。
為什么使用csv.reader()而不是直接split(',')?
雖然我們可以用 line.split(',') 來分割每行內(nèi)容,但這樣做存在諸多隱患:
| 問題 | 示例說明 |
|---|---|
| 引號內(nèi)的逗號被錯誤分割 | "Apple, Red", "2023-01-01" → 錯誤拆成 ['Apple', ' Red', '2023-01-01'] |
| 字段為空導(dǎo)致索引錯位 | "A,,C" → 僅兩個元素,訪問第2個會越界 |
| 多行文本被破壞 | 若某字段包含換行符,split 會將其視為新行 |
而 csv.reader() 內(nèi)部實現(xiàn)了完整的 CSV 解析邏輯,能正確處理:
- 帶引號的字段(
"value with comma") - 空字段(連續(xù)逗號)
- 包含換行符的字段
- 轉(zhuǎn)義字符(如
""表示一個雙引號)
所以,永遠(yuǎn)不要用 .split(',') 處理真正的 CSV!
實戰(zhàn)案例一:讀取學(xué)生成績表
假設(shè)我們有一個名為 grades.csv 的文件,內(nèi)容如下:
姓名,數(shù)學(xué),英語,物理,總分 張三,85,92,78,255 李四,90,88,95,273 王五,76,84,80,240 趙六,95,96,94,285
現(xiàn)在我們要讀取這份成績表,并計算平均分。
完整代碼實現(xiàn)
import csv
def calculate_average():
total_score = 0
count = 0
with open('grades.csv', 'r', encoding='utf-8') as file:
# 創(chuàng)建 reader 對象
reader = csv.reader(file)
# 跳過第一行(標(biāo)題行)
header = next(reader)
print(f"表頭: {header}")
# 遍歷剩余行
for row in reader:
name = row[0]
scores = [float(x) for x in row[1:-1]] # 數(shù)學(xué)、英語、物理
total = float(row[-1]) # 總分
avg = sum(scores) / len(scores)
total_score += total
count += 1
print(f"{name}: 平均分={avg:.2f}, 總分={total}")
if count > 0:
overall_avg = total_score / count
print(f"\n?? 全體學(xué)生平均總分: {overall_avg:.2f}")
calculate_average()
輸出結(jié)果
表頭: ['姓名', '數(shù)學(xué)', '英語', '物理', '總分']
張三: 平均分=85.00, 總分=255
李四: 平均分=91.00, 總分=273
王五: 平均分=80.00, 總分=240
趙六: 平均分=95.00, 總分=285
?? 全體學(xué)生平均總分: 263.00
關(guān)鍵點總結(jié):
- 使用
next(reader)顯式跳過標(biāo)題行。 - 列表切片
[1:-1]提取非標(biāo)題和非總分的科目。 - 類型轉(zhuǎn)換
float(x)必須謹(jǐn)慎,防止無效值報錯。
進(jìn)階技巧:自定義分隔符與引號設(shè)置
默認(rèn)情況下,csv.reader() 使用英文逗號 , 作為分隔符,雙引號 " 作為字段包裹符。但在某些場景下,可能需要修改這些行為。
支持分號分隔的CSV(如歐洲地區(qū)常用)
例如,data_semicolon.csv 文件內(nèi)容:
ID;Name;Age;City 1;Alice;25;Berlin 2;Bob;30;Munich 3;Charlie;28;Hamburg
import csv
with open('data_semicolon.csv', 'r', encoding='utf-8') as file:
# 指定分隔符為分號
reader = csv.reader(file, delimiter=';')
for row in reader:
print(row)
輸出:
['ID', 'Name', 'Age', 'City']
['1', 'Alice', '25', 'Berlin']
['2', 'Bob', '30', 'Munich']
['3', 'Charlie', '28', 'Hamburg']
特殊引號配置:避免誤判
當(dāng)字段內(nèi)包含引號時,有時系統(tǒng)會使用其他符號作為引用標(biāo)記。比如使用單引號 ' 包裹字段。
ID,Name,Description 1,'John','This is a "test" field' 2,'Jane','She said: "Hello!"'
此時應(yīng)設(shè)置:
reader = csv.reader(file, delimiter=',', quotechar="'")
這樣就能正確識別 '"test"' 為完整字段,而不是拆成多個部分。
外部數(shù)據(jù)源實戰(zhàn):從網(wǎng)頁下載CSV并讀取
現(xiàn)實世界中,很多公開數(shù)據(jù)集都以 CSV 格式提供。例如,世界衛(wèi)生組織(WHO)發(fā)布的全球疫情數(shù)據(jù)。
我們可以使用 requests 庫下載遠(yuǎn)程 CSV,再用 csv.reader() 解析。
示例:獲取病例數(shù)據(jù)
import csv
import requests
from io import StringIO
# 從 WHO 官方獲取數(shù)據(jù)(示例鏈接,實際可用)
url = "https://covid.ourworldindata.org/data/owid-covid-data.csv"
try:
response = requests.get(url)
response.raise_for_status() # 檢查請求是否成功
# 將響應(yīng)內(nèi)容轉(zhuǎn)為字符串流
data_stream = StringIO(response.text)
# 用 csv.reader 讀取
reader = csv.reader(data_stream)
# 獲取表頭
headers = next(reader)
print("?? 數(shù)據(jù)字段:", headers)
# 查找特定國家的數(shù)據(jù)
country_name = "China"
found = False
for row in reader:
if row[2] == country_name: # 假設(shè)第3列為國家名
date = row[3] # 日期
new_cases = row[7] # 新增病例數(shù)
print(f"?? {date} - {country_name} 新增病例: {new_cases}")
found = True
break
if not found:
print(f"? 未找到 {country_name} 的數(shù)據(jù)")
except Exception as e:
print(f"?? 讀取失敗: {e}")
此方法適用于任何可通過 HTTP 獲取的 CSV 資源,無需本地保存文件。
數(shù)據(jù)可視化前奏:用csv.reader構(gòu)建數(shù)據(jù)結(jié)構(gòu)
在進(jìn)行數(shù)據(jù)分析或繪圖之前,我們需要將原始數(shù)據(jù)轉(zhuǎn)換為適合處理的結(jié)構(gòu)。csv.reader() 是構(gòu)建這一過程的第一步。
構(gòu)造字典列表(List of Dicts)
import csv
def read_csv_to_dicts(filename):
data = []
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.reader(file)
headers = next(reader) # 第一行作為鍵
for row in reader:
record = {}
for i, value in enumerate(row):
record[headers[i]] = value
data.append(record)
return data
# 使用
students = read_csv_to_dicts('grades.csv')
for student in students:
print(f"{student['姓名']} - 數(shù)學(xué): {student['數(shù)學(xué)']}")
輸出:
張三 - 數(shù)學(xué): 85
李四 - 數(shù)學(xué): 90
王五 - 數(shù)學(xué): 76
趙六 - 數(shù)學(xué): 95
這種方式特別適合后續(xù)與 Pandas 配合使用,或用于 JSON 序列化。
常見陷阱與解決方案
盡管 csv.reader() 功能強大,但在實際使用中仍容易踩坑。
陷阱1:編碼問題導(dǎo)致亂碼
如果文件是 UTF-8 編碼,但打開時未指定 encoding='utf-8',可能會出現(xiàn):
UnicodeDecodeError: 'cp936' codec can't decode byte ...
解決方案:
with open('data.csv', 'r', encoding='utf-8') as file:
reader = csv.reader(file)
建議始終顯式聲明編碼,避免系統(tǒng)默認(rèn)編碼不匹配。
陷阱2:空行或空白行引發(fā)異常
有些 CSV 文件末尾有多余空行,或中間插入了空行。
姓名,數(shù)學(xué),英語 張三,85,92 李四,90,88
若直接遍歷,row 可能是 [],導(dǎo)致后續(xù)操作出錯。
安全做法:
for row in reader:
if not row: # 跳過空行
continue
print(row)
陷阱3:字段值缺失或非法數(shù)值
當(dāng)某字段為空或非數(shù)字時,強制轉(zhuǎn)換為 float 會拋出異常。
scores = [float(x) for x in row[1:-1]]
如果某個字段是空字符串 "",就會觸發(fā) ValueError: could not convert string to float:
解決方案:添加容錯處理
def safe_float(value, default=0.0):
try:
return float(value) if value.strip() else default
except (ValueError, TypeError):
return default
# 使用
scores = [safe_float(x) for x in row[1:-1]]
與csv.DictReader對比:你該選哪個?
雖然 csv.reader() 更底層,但 csv.DictReader 更高級,尤其適合有表頭的文件。
何時選擇csv.reader()?
- 你需要高性能讀取大量數(shù)據(jù)。
- 字段順序嚴(yán)格固定。
- 你是初學(xué)者,想理解底層機制。
何時選擇csv.DictReader?
- 你有清晰的列名。
- 你想通過字段名訪問數(shù)據(jù),提高代碼可讀性。
- 你正在做快速原型開發(fā)或分析。
import csv
with open('grades.csv', 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
print(f"{row['姓名']} 的數(shù)學(xué)成績是 {row['數(shù)學(xué)']}")
實用工具函數(shù)封裝:一鍵讀取帶驗證的CSV
為了提升復(fù)用性,我們可以封裝一個通用函數(shù),支持自動跳過空行、處理缺失值、驗證列數(shù)等。
import csv
from typing import List, Dict, Any
def safe_read_csv(filename: str, expected_cols: int = None, skip_empty: bool = True) -> List[Dict[str, Any]]:
"""
安全讀取CSV文件,返回字典列表
:param filename: 文件路徑
:param expected_cols: 期望列數(shù),用于校驗
:param skip_empty: 是否跳過空行
:return: 數(shù)據(jù)列表
"""
data = []
try:
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.reader(file)
headers = next(reader)
if expected_cols and len(headers) != expected_cols:
raise ValueError(f"列數(shù)不符!期望 {expected_cols},實際 {len(headers)}")
for line_num, row in enumerate(reader, start=2):
if skip_empty and not row:
continue
if expected_cols and len(row) != expected_cols:
print(f"?? 第 {line_num} 行列數(shù)不符,跳過")
continue
record = dict(zip(headers, row))
data.append(record)
except FileNotFoundError:
print(f"? 文件不存在: {filename}")
except Exception as e:
print(f"? 讀取失敗: {e}")
return data
# 使用
records = safe_read_csv('grades.csv', expected_cols=5)
for r in records:
print(r)
這個函數(shù)具備:
- 錯誤捕獲
- 列數(shù)校驗
- 空行跳過
- 自動映射為字典
- 友好提示信息
結(jié)語:掌握csv.reader(),開啟數(shù)據(jù)處理之旅
csv.reader() 雖然看似簡單,卻是連接程序與真實世界數(shù)據(jù)的重要橋梁。它不僅幫助我們避開字符串處理的陷阱,還為我們打下了后續(xù)使用 Pandas、數(shù)據(jù)分析、自動化報表等高級技能的基礎(chǔ)。
無論你是:
- 一名剛?cè)腴T的程序員,
- 一位需要處理報表的業(yè)務(wù)人員,
- 還是一位致力于數(shù)據(jù)可視化的工程師,
到此這篇關(guān)于深入理解Python CSV文件讀取與csv.reader函數(shù)使用指南的文章就介紹到這了,更多相關(guān)Python CSV文件讀取內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python3 面向?qū)ο骭_類的內(nèi)置屬性與方法的實例代碼
這篇文章主要介紹了python3 面向?qū)ο骭_類的內(nèi)置屬性與方法的實例代碼,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-11-11
python3使用logging包,如何把日志寫到系統(tǒng)的rsyslog中
這篇文章主要介紹了python3使用logging包,如何把日志寫到系統(tǒng)的rsyslog中的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
Python在線編譯器Lightly輕松實現(xiàn)貪吃蛇游戲
今天我將帶領(lǐng)大家使用Python的Pygame庫在Lightly在線編譯器中實現(xiàn)一個經(jīng)典的貪吃蛇游戲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2025-09-09
django框架實現(xiàn)一次性上傳多個文件功能示例【批量上傳】
這篇文章主要介紹了django框架實現(xiàn)一次性上傳多個文件功能,結(jié)合實例形式分析了Django框架批量上傳相關(guān)實現(xiàn)技巧與操作注意事項,需要的朋友可以參考下2019-06-06

