最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python使用csv模塊進行文件讀寫的操作詳解

 更新時間:2026年05月06日 09:18:43   作者:Python游俠  
本文詳細介紹了CSV的基本概念、語法和核心特點,通過實際案例講解了如何使用Python的csv模塊進行數(shù)據(jù)讀取、分析、清洗、轉換、合并和拆分等操作,同時,還介紹了高級技巧、性能優(yōu)化方法和實戰(zhàn)工具的構建,并提供了常見問題的解決方案及替代方案的選擇

一、核心概念解析

1.1 基礎定義:CSV到底是什么?

CSV的全稱是"Comma-Separated Values"(逗號分隔值),但它有個小秘密:并不總是用逗號。

看看這幾個常見的CSV變體:

# 典型的CSV格式
name,age,city
張三,30,北京
李四,25,上海

# 用分號分隔(歐洲常見)
name;age;city
張三;30;北京
李四;25;上海

# 用制表符分隔(TSV文件)
name	age	city
張三	30	北京
李四	25	上海

# 帶引號的CSV(包含逗號時)
product,price,description
"蘋果,紅富士",5.8,"新鮮,甜"
香蕉,3.2,"進口,黃色"

CSV的本質是純文本表格,由三部分組成:

  1. 表頭行(可選):定義每列的名稱
  2. 數(shù)據(jù)行:每行一條記錄
  3. 分隔符:通常是逗號,但也可能是其他字符

1.2 基本語法:csv模塊的四大金剛

csv模塊的核心是四個類/函數(shù):

import csv

# 1. 讀取CSV文件
with open('data.csv', 'r', encoding='utf-8') as file:
    reader = csv.reader(file)
    for row in reader:
        print(row)  # 每行是一個列表

# 2. 寫入CSV文件
data = [
    ['name', 'age', 'city'],
    ['張三', '30', '北京'],
    ['李四', '25', '上海']
]

with open('output.csv', 'w', encoding='utf-8', newline='') as file:
    writer = csv.writer(file)
    writer.writerows(data)

# 3. 用字典方式讀?。ㄍ扑]!)
with open('data.csv', 'r', encoding='utf-8') as file:
    reader = csv.DictReader(file)
    for row in reader:
        print(row['name'], row['age'])  # 通過列名訪問

# 4. 用字典方式寫入
data = [
    {'name': '張三', 'age': '30', 'city': '北京'},
    {'name': '李四', 'age': '25', 'city': '上海'}
]

with open('output_dict.csv', 'w', encoding='utf-8', newline='') as file:
    fieldnames = ['name', 'age', 'city']
    writer = csv.DictWriter(file, fieldnames=fieldnames)
    writer.writeheader()  # 寫入表頭
    writer.writerows(data)

注意那個newline=''參數(shù):在Windows上,如果不加這個,每行后面會多一個空行。這是Python處理文本文件的一個坑,記住就好。

1.3 核心特點:為什么選擇csv模塊?

  1. 零依賴:Python自帶,不用安裝任何東西
  2. 內存友好:流式處理,再大的文件也不怕
  3. 靈活配置:分隔符、引號字符、編碼全都可以自定義
  4. 簡單易用:幾行代碼就能完成復雜操作
  5. 兼容性好:處理各種"奇怪"的CSV文件

二、應用場景詳解

2.1 讀取和分析數(shù)據(jù)

假設你有一個銷售數(shù)據(jù)文件sales.csv

date,product,quantity,price,region
2023-01-15,Widget-A,10,29.99,North
2023-01-15,Gadget-X,5,99.99,South
2023-01-16,Widget-A,8,29.99,East
2023-01-16,Thingy-B,3,149.99,West

讓我們用csv模塊來分析它:

# analyze_sales.py
import csv
from collections import defaultdict
from datetime import datetime

def analyze_sales_data(filepath):
    """
    分析銷售數(shù)據(jù)
    """
    # 存儲統(tǒng)計結果
    stats = {
        'total_sales': 0,
        'total_quantity': 0,
        'by_product': defaultdict(float),
        'by_region': defaultdict(float),
        'by_date': defaultdict(float)
    }
    
    with open(filepath, 'r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        
        for row in reader:
            try:
                # 轉換數(shù)據(jù)類型
                quantity = int(row['quantity'])
                price = float(row['price'])
                date_str = row['date']
                
                # 計算銷售額
                sales = quantity * price
                
                # 更新統(tǒng)計
                stats['total_sales'] += sales
                stats['total_quantity'] += quantity
                stats['by_product'][row['product']] += sales
                stats['by_region'][row['region']] += sales
                stats['by_date'][date_str] += sales
                
            except (ValueError, KeyError) as e:
                print(f"數(shù)據(jù)格式錯誤: {row}, 錯誤: {e}")
                continue
    
    return stats

def print_statistics(stats):
    """
    打印統(tǒng)計結果
    """
    print("=" * 50)
    print("銷售數(shù)據(jù)分析報告")
    print("=" * 50)
    
    print(f"\n總銷售額: ${stats['total_sales']:.2f}")
    print(f"總銷售數(shù)量: {stats['total_quantity']}")
    
    print("\n按產品統(tǒng)計:")
    for product, sales in sorted(stats['by_product'].items(), 
                                 key=lambda x: x[1], reverse=True):
        print(f"  {product}: ${sales:.2f}")
    
    print("\n按地區(qū)統(tǒng)計:")
    for region, sales in sorted(stats['by_region'].items(),
                                key=lambda x: x[1], reverse=True):
        print(f"  {region}: ${sales:.2f}")
    
    print("\n按日期統(tǒng)計:")
    for date, sales in sorted(stats['by_date'].items()):
        print(f"  {date}: ${sales:.2f}")

# 生成測試數(shù)據(jù)
def create_sample_data():
    """創(chuàng)建示例銷售數(shù)據(jù)"""
    data = [
        ['date', 'product', 'quantity', 'price', 'region'],
        ['2023-01-15', 'Widget-A', 10, 29.99, 'North'],
        ['2023-01-15', 'Gadget-X', 5, 99.99, 'South'],
        ['2023-01-16', 'Widget-A', 8, 29.99, 'East'],
        ['2023-01-16', 'Thingy-B', 3, 149.99, 'West'],
        ['2023-01-16', 'Gadget-X', 12, 99.99, 'North'],
        ['2023-01-17', 'Widget-A', 15, 27.50, 'South'],
    ]
    
    with open('sales.csv', 'w', encoding='utf-8', newline='') as file:
        writer = csv.writer(file)
        writer.writerows(data)
    
    print("示例數(shù)據(jù)已創(chuàng)建: sales.csv")

if __name__ == "__main__":
    # 創(chuàng)建測試數(shù)據(jù)
    create_sample_data()
    
    # 分析數(shù)據(jù)
    stats = analyze_sales_data('sales.csv')
    
    # 打印結果
    print_statistics(stats)

2.2 數(shù)據(jù)清洗和轉換

現(xiàn)實中的數(shù)據(jù)很少是完美的。讓我們看看如何處理各種"臟數(shù)據(jù)":

# clean_data.py
import csv
import re

def clean_csv_file(input_file, output_file):
    """
    清洗CSV數(shù)據(jù)
    """
    cleaned_rows = []
    
    with open(input_file, 'r', encoding='utf-8') as infile:
        reader = csv.DictReader(infile)
        fieldnames = reader.fieldnames
        
        for i, row in enumerate(reader, 1):
            cleaned_row = {}
            
            for field in fieldnames:
                original_value = row.get(field, '')
                cleaned_value = clean_field(field, original_value)
                cleaned_row[field] = cleaned_value
            
            # 檢查是否有必要的數(shù)據(jù)
            if is_valid_row(cleaned_row):
                cleaned_rows.append(cleaned_row)
            else:
                print(f"跳過第{i}行無效數(shù)據(jù): {row}")
    
    # 寫入清洗后的數(shù)據(jù)
    with open(output_file, 'w', encoding='utf-8', newline='') as outfile:
        writer = csv.DictWriter(outfile, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerows(cleaned_rows)
    
    print(f"數(shù)據(jù)清洗完成: {len(cleaned_rows)} 行有效數(shù)據(jù)")

def clean_field(field_name, value):
    """
    根據(jù)字段類型清洗數(shù)據(jù)
    """
    if not value:
        return value
    
    # 去除首尾空白
    value = value.strip()
    
    # 根據(jù)不同字段類型進行清洗
    if 'email' in field_name.lower():
        return clean_email(value)
    elif 'phone' in field_name.lower():
        return clean_phone(value)
    elif 'date' in field_name.lower():
        return clean_date(value)
    elif 'price' in field_name.lower() or 'amount' in field_name.lower():
        return clean_number(value)
    else:
        return value

def clean_email(email):
    """清洗郵箱地址"""
    email = email.lower().strip()
    # 簡單的郵箱格式驗證
    if '@' in email and '.' in email.split('@')[1]:
        return email
    return ''

def clean_phone(phone):
    """清洗電話號碼"""
    # 移除非數(shù)字字符
    digits = re.sub(r'\D', '', phone)
    
    if len(digits) == 11:  # 中國手機號
        return digits
    elif len(digits) == 10:  # 固定電話
        return digits
    else:
        return ''

def clean_date(date_str):
    """清洗日期"""
    # 嘗試不同的日期格式
    formats = ['%Y-%m-%d', '%Y/%m/%d', '%Y年%m月%d日', '%d/%m/%Y']
    
    for fmt in formats:
        try:
            from datetime import datetime
            dt = datetime.strptime(date_str, fmt)
            return dt.strftime('%Y-%m-%d')  # 統(tǒng)一格式
        except ValueError:
            continue
    
    return date_str  # 無法解析,返回原值

def clean_number(number_str):
    """清洗數(shù)字"""
    # 移除貨幣符號、千分位分隔符等
    cleaned = re.sub(r'[^\d\.-]', '', number_str)
    
    try:
        return str(float(cleaned))
    except ValueError:
        return '0'

def is_valid_row(row):
    """檢查行是否有效"""
    # 必須有姓名
    if not row.get('name', '').strip():
        return False
    
    # 郵箱必須有效(如果有的話)
    email = row.get('email', '')
    if email and '@' not in email:
        return False
    
    return True

def create_dirty_data():
    """創(chuàng)建包含臟數(shù)據(jù)的測試文件"""
    dirty_data = [
        ['name', 'email', 'phone', 'join_date', 'amount'],
        [' 張三 ', 'ZHANGSAN@EXAMPLE.COM', '138-0013-8000', '2023-01-15', '¥1,000.50'],
        ['李四', 'lisi.example.com', '010-62345678', '2023/02/20', '2,500.00'],
        ['', 'wangwu@example.com', '13912345678', '2023年03月15日', '1500'],
        ['趙六', 'zhaoliu@example', '123-4567', '無效日期', 'ABC'],
        ['錢七', 'qianqi@example.com', '15012345678', '20/04/2023', '3,000.00'],
    ]
    
    with open('dirty_data.csv', 'w', encoding='utf-8', newline='') as file:
        writer = csv.writer(file)
        writer.writerows(dirty_data)
    
    print("臟數(shù)據(jù)測試文件已創(chuàng)建: dirty_data.csv")

if __name__ == "__main__":
    # 創(chuàng)建測試數(shù)據(jù)
    create_dirty_data()
    
    # 清洗數(shù)據(jù)
    clean_csv_file('dirty_data.csv', 'cleaned_data.csv')
    
    # 顯示清洗結果
    print("\n清洗前后對比:")
    print("-" * 50)
    
    with open('dirty_data.csv', 'r', encoding='utf-8') as f:
        print("原始數(shù)據(jù):")
        for line in f:
            print("  ", line.strip())
    
    print("\n清洗后數(shù)據(jù):")
    with open('cleaned_data.csv', 'r', encoding='utf-8') as f:
        for line in f:
            print("  ", line.strip())

2.3 合并和拆分文件

工作中經(jīng)常需要處理多個CSV文件,比如每月的數(shù)據(jù)分開存儲,但分析時需要合并:

# merge_split_csv.py
import csv
import os
from glob import glob

def merge_csv_files(pattern, output_file):
    """
    合并多個CSV文件
    
    參數(shù):
        pattern: 文件匹配模式,如 'data/*.csv'
        output_file: 合并后的輸出文件
    """
    all_data = []
    headers = None
    
    for filename in glob(pattern):
        print(f"處理文件: {filename}")
        
        with open(filename, 'r', encoding='utf-8') as file:
            reader = csv.DictReader(file)
            
            # 檢查表頭是否一致
            if headers is None:
                headers = reader.fieldnames
            elif headers != reader.fieldnames:
                print(f"警告: {filename} 的表頭不一致,跳過")
                continue
            
            # 讀取數(shù)據(jù)
            for row in reader:
                all_data.append(row)
    
    if not all_data:
        print("沒有找到可合并的數(shù)據(jù)")
        return
    
    # 寫入合并后的文件
    with open(output_file, 'w', encoding='utf-8', newline='') as file:
        writer = csv.DictWriter(file, fieldnames=headers)
        writer.writeheader()
        writer.writerows(all_data)
    
    print(f"合并完成: 共 {len(all_data)} 行數(shù)據(jù),保存到 {output_file}")

def split_csv_by_column(input_file, column_name, output_dir):
    """
    按某一列的值拆分CSV文件
    
    參數(shù):
        input_file: 輸入文件
        column_name: 按此列拆分
        output_dir: 輸出目錄
    """
    # 確保輸出目錄存在
    os.makedirs(output_dir, exist_ok=True)
    
    # 按列值分組數(shù)據(jù)
    groups = {}
    
    with open(input_file, 'r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        headers = reader.fieldnames
        
        for row in reader:
            key = row.get(column_name, 'unknown')
            
            if key not in groups:
                groups[key] = []
            
            groups[key].append(row)
    
    # 為每個組創(chuàng)建文件
    for key, rows in groups.items():
        # 創(chuàng)建安全的文件名
        safe_key = "".join(c for c in str(key) if c.isalnum() or c in (' ', '-', '_')).rstrip()
        output_file = os.path.join(output_dir, f"{safe_key}.csv")
        
        with open(output_file, 'w', encoding='utf-8', newline='') as file:
            writer = csv.DictWriter(file, fieldnames=headers)
            writer.writeheader()
            writer.writerows(rows)
        
        print(f"創(chuàng)建文件: {output_file} ({len(rows)} 行)")
    
    print(f"拆分完成: 共創(chuàng)建 {len(groups)} 個文件")

def create_monthly_data():
    """創(chuàng)建月度測試數(shù)據(jù)"""
    months = ['2023-01', '2023-02', '2023-03']
    
    for month in months:
        filename = f"monthly_data_{month}.csv"
        data = [
            ['date', 'product', 'sales', 'region'],
            [f'{month}-10', 'Product-A', '1000', 'North'],
            [f'{month}-15', 'Product-B', '1500', 'South'],
            [f'{month}-20', 'Product-A', '800', 'East'],
        ]
        
        with open(filename, 'w', encoding='utf-8', newline='') as file:
            writer = csv.writer(file)
            writer.writerows(data)
        
        print(f"創(chuàng)建: {filename}")

if __name__ == "__main__":
    print("=== CSV文件合并與拆分演示 ===\n")
    
    # 創(chuàng)建測試數(shù)據(jù)
    print("1. 創(chuàng)建月度測試數(shù)據(jù)...")
    create_monthly_data()
    
    # 合并文件
    print("\n2. 合并月度數(shù)據(jù)...")
    merge_csv_files('monthly_data_*.csv', 'merged_quarterly.csv')
    
    # 拆分文件
    print("\n3. 按地區(qū)拆分數(shù)據(jù)...")
    split_csv_by_column('merged_quarterly.csv', 'region', 'split_by_region')
    
    # 顯示結果
    print("\n" + "=" * 50)
    print("生成的文件:")
    for file in ['merged_quarterly.csv', 'split_by_region']:
        if os.path.exists(file):
            if os.path.isdir(file):
                print(f"目錄: {file}/")
                for f in os.listdir(file):
                    print(f"  - {f}")
            else:
                print(f"文件: {file}")

三、高級技巧

3.1 處理特殊格式的CSV

不是所有的CSV文件都那么"標準"。讓我們看看如何處理各種特殊情況:

# special_csv_formats.py
import csv

def read_excel_csv():
    """
    處理從Excel導出的CSV
    Excel導出的CSV常有BOM和特殊編碼
    """
    files_to_try = [
        ('utf-8-sig', 'excel_utf8_bom.csv'),  # UTF-8 with BOM
        ('gbk', 'excel_gbk.csv'),             # GBK編碼(中文Windows)
        ('utf-8', 'excel_utf8.csv'),          # 普通UTF-8
    ]
    
    for encoding, filename in files_to_try:
        try:
            with open(filename, 'r', encoding=encoding) as file:
                reader = csv.reader(file)
                data = list(reader)
            
            print(f"成功讀取 {filename} (編碼: {encoding})")
            print(f"  表頭: {data[0]}")
            print(f"  行數(shù): {len(data)}")
            break
        except (UnicodeDecodeError, FileNotFoundError):
            continue

def handle_custom_delimiters():
    """處理自定義分隔符"""
    # 用分號分隔的文件
    with open('european_format.csv', 'w', encoding='utf-8') as f:
        f.write("name;age;city\n")
        f.write("張三;30;北京\n")
        f.write("李四;25;上海\n")
    
    # 讀取時指定分隔符
    with open('european_format.csv', 'r', encoding='utf-8') as file:
        reader = csv.reader(file, delimiter=';')
        for row in reader:
            print(f"分隔符';': {row}")
    
    # TSV文件(制表符分隔)
    with open('data.tsv', 'w', encoding='utf-8') as f:
        f.write("name\tage\tcity\n")
        f.write("張三\t30\t北京\n")
        f.write("李四\t25\t上海\n")
    
    with open('data.tsv', 'r', encoding='utf-8') as file:
        reader = csv.reader(file, delimiter='\t')
        for row in reader:
            print(f"分隔符'\\t': {row}")

def handle_quoted_data():
    """處理帶引號的數(shù)據(jù)"""
    # 創(chuàng)建包含逗號和引號的數(shù)據(jù)
    tricky_data = [
        ['name', 'description', 'price'],
        ['Apple', 'Red, delicious apple', '5.8'],
        ['Banana', 'Yellow "sweet" banana', '3.2'],
        ['Orange Juice', 'Fresh, 100% pure orange "juice"', '12.5'],
    ]
    
    with open('quoted_data.csv', 'w', encoding='utf-8', newline='') as file:
        writer = csv.writer(file, quoting=csv.QUOTE_ALL)  # 所有字段都加引號
        writer.writerows(tricky_data)
    
    print("\n帶引號的數(shù)據(jù)文件已創(chuàng)建")
    
    # 讀取時處理引號
    with open('quoted_data.csv', 'r', encoding='utf-8') as file:
        reader = csv.reader(file)
        for row in reader:
            print(f"原始行: {row}")

def handle_large_files():
    """處理大文件的內存友好方式"""
    print("\n大文件處理策略:")
    print("1. 流式處理,一次一行,不加載到內存")
    print("2. 分批處理,特別是需要排序或聚合時")
    print("3. 使用生成器避免內存累積")
    
    def process_large_file(filename, chunk_size=1000):
        """分批處理大文件"""
        with open(filename, 'r', encoding='utf-8') as file:
            reader = csv.DictReader(file)
            
            chunk = []
            for i, row in enumerate(reader, 1):
                chunk.append(row)
                
                if len(chunk) >= chunk_size:
                    yield chunk
                    chunk = []
            
            if chunk:  # 最后一批
                yield chunk
    
    # 模擬處理
    print("\n模擬處理大文件(分塊):")
    for chunk_num, chunk in enumerate(process_large_file('large_data.csv', chunk_size=2), 1):
        print(f"  處理第{chunk_num}塊: {len(chunk)} 行")
        # 這里可以處理每個數(shù)據(jù)塊
        # 比如寫入數(shù)據(jù)庫、進行聚合計算等

if __name__ == "__main__":
    print("=== 特殊CSV格式處理 ===\n")
    
    # 處理自定義分隔符
    print("1. 自定義分隔符處理:")
    handle_custom_delimiters()
    
    # 處理帶引號的數(shù)據(jù)
    print("\n2. 帶引號數(shù)據(jù)處理:")
    handle_quoted_data()
    
    # 大文件處理
    print("\n3. 大文件處理策略:")
    handle_large_files()

3.2 性能優(yōu)化技巧

# csv_performance.py
import csv
import time
import random
from memory_profiler import profile

def create_large_csv(filename, num_rows=100000):
    """創(chuàng)建大型測試CSV文件"""
    print(f"創(chuàng)建大型測試文件: {filename} ({num_rows} 行)")
    
    with open(filename, 'w', encoding='utf-8', newline='') as file:
        writer = csv.writer(file)
        
        # 寫入表頭
        writer.writerow(['id', 'name', 'value', 'category', 'timestamp'])
        
        # 寫入數(shù)據(jù)
        for i in range(num_rows):
            writer.writerow([
                i + 1,
                f'Item-{random.randint(1, 1000)}',
                random.uniform(1, 1000),
                random.choice(['A', 'B', 'C', 'D']),
                f'2023-{random.randint(1,12):02d}-{random.randint(1,28):02d}'
            ])
    
    print("文件創(chuàng)建完成")

def naive_processing(filename):
    """原始方法:一次性加載所有數(shù)據(jù)"""
    print("\n方法1: 一次性加載所有數(shù)據(jù)")
    start = time.time()
    
    with open(filename, 'r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        all_data = list(reader)  # 這里會加載所有數(shù)據(jù)到內存
    
    # 處理數(shù)據(jù)
    total = 0
    for row in all_data:
        total += float(row['value'])
    
    elapsed = time.time() - start
    print(f"  處理了 {len(all_data)} 行數(shù)據(jù)")
    print(f"  總和: {total:.2f}")
    print(f"  耗時: {elapsed:.2f} 秒")
    
    return elapsed

def stream_processing(filename):
    """流式處理:一次處理一行"""
    print("\n方法2: 流式處理(一次一行)")
    start = time.time()
    
    total = 0
    count = 0
    
    with open(filename, 'r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        
        for row in reader:
            total += float(row['value'])
            count += 1
    
    elapsed = time.time() - start
    print(f"  處理了 {count} 行數(shù)據(jù)")
    print(f"  總和: {total:.2f}")
    print(f"  耗時: {elapsed:.2f} 秒")
    
    return elapsed

def batch_processing(filename, batch_size=10000):
    """批量處理:分批處理數(shù)據(jù)"""
    print(f"\n方法3: 批量處理(每批 {batch_size} 行)")
    start = time.time()
    
    total = 0
    count = 0
    batch = []
    
    with open(filename, 'r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        
        for row in reader:
            batch.append(float(row['value']))
            count += 1
            
            if len(batch) >= batch_size:
                # 處理一個批次
                total += sum(batch)
                batch = []  # 清空批次
        
        # 處理最后一批
        if batch:
            total += sum(batch)
    
    elapsed = time.time() - start
    print(f"  處理了 {count} 行數(shù)據(jù)")
    print(f"  總和: {total:.2f}")
    print(f"  耗時: {elapsed:.2f} 秒")
    
    return elapsed

def optimized_writing(filename, num_rows=10000):
    """優(yōu)化寫入性能"""
    print(f"\n寫入性能優(yōu)化 ({num_rows} 行):")
    
    # 方法1: 逐行寫入
    start = time.time()
    with open('slow_write.csv', 'w', encoding='utf-8', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(['id', 'value'])
        
        for i in range(num_rows):
            writer.writerow([i, i * 1.5])  # 每次調用writerow
    
    elapsed1 = time.time() - start
    print(f"  逐行寫入: {elapsed1:.2f} 秒")
    
    # 方法2: 批量寫入
    start = time.time()
    with open('fast_write.csv', 'w', encoding='utf-8', newline='') as file:
        writer = csv.writer(file)
        writer.writerow(['id', 'value'])
        
        # 準備所有數(shù)據(jù)
        all_data = [[i, i * 1.5] for i in range(num_rows)]
        writer.writerows(all_data)  # 一次寫入所有行
    
    elapsed2 = time.time() - start
    print(f"  批量寫入: {elapsed2:.2f} 秒")
    print(f"  速度提升: {elapsed1/elapsed2:.1f} 倍")

if __name__ == "__main__":
    print("=== CSV性能優(yōu)化技巧 ===\n")
    
    # 創(chuàng)建測試數(shù)據(jù)
    test_file = 'large_test_data.csv'
    create_large_csv(test_file, num_rows=50000)
    
    # 測試不同處理方法的性能
    times = []
    times.append(('一次性加載', naive_processing(test_file)))
    times.append(('流式處理', stream_processing(test_file)))
    times.append(('批量處理', batch_processing(test_file)))
    
    # 寫入性能測試
    optimized_writing('test_write.csv', num_rows=10000)
    
    # 總結
    print("\n" + "=" * 50)
    print("性能總結:")
    for method, t in times:
        print(f"  {method}: {t:.2f} 秒")

3.3 實戰(zhàn):構建CSV處理工具

讓我們構建一個實用的CSV處理工具,集成各種常用功能:

# csv_toolkit.py
"""
CSV處理工具箱

一個實用的命令行工具,集成各種CSV處理功能
"""
import csv
import argparse
import sys
import os
from pathlib import Path

class CSVToolkit:
    """CSV處理工具箱"""
    
    def __init__(self):
        self.commands = {
            'view': self.view_csv,
            'head': self.head_csv,
            'tail': self.tail_csv,
            'stats': self.csv_stats,
            'filter': self.filter_csv,
            'select': self.select_columns,
            'sample': self.sample_csv,
        }
    
    def run(self):
        """運行工具箱"""
        parser = argparse.ArgumentParser(description='CSV處理工具箱')
        parser.add_argument('command', choices=self.commands.keys(), 
                          help='要執(zhí)行的操作')
        parser.add_argument('file', help='CSV文件路徑')
        parser.add_argument('-o', '--output', help='輸出文件路徑')
        parser.add_argument('-n', '--lines', type=int, default=10,
                          help='顯示的行數(shù)(用于head/tail)')
        parser.add_argument('-c', '--columns', help='選擇的列,用逗號分隔')
        parser.add_argument('-f', '--filter', help='過濾條件,格式: 列名=值')
        
        args = parser.parse_args()
        
        # 檢查文件是否存在
        if not os.path.exists(args.file):
            print(f"錯誤: 文件 '{args.file}' 不存在")
            sys.exit(1)
        
        # 執(zhí)行命令
        self.commands[args.command](args)
    
    def view_csv(self, args):
        """查看CSV文件內容"""
        with open(args.file, 'r', encoding='utf-8') as file:
            reader = csv.reader(file)
            
            for i, row in enumerate(reader):
                # 美化輸出
                formatted = ' | '.join(f'{cell:<20}' for cell in row)
                print(formatted)
                
                # 顯示表頭分隔線
                if i == 0:
                    print('-' * len(formatted))
    
    def head_csv(self, args):
        """顯示文件前n行"""
        with open(args.file, 'r', encoding='utf-8') as file:
            reader = csv.reader(file)
            
            for i, row in enumerate(reader):
                if i >= args.lines + 1:  # +1 為了包含表頭
                    break
                print(', '.join(row))
    
    def tail_csv(self, args):
        """顯示文件后n行"""
        with open(args.file, 'r', encoding='utf-8') as file:
            lines = file.readlines()
            
        # 顯示最后n行
        for line in lines[-args.lines:]:
            print(line.rstrip())
    
    def csv_stats(self, args):
        """顯示CSV文件統(tǒng)計信息"""
        with open(args.file, 'r', encoding='utf-8') as file:
            reader = csv.reader(file)
            data = list(reader)
        
        if not data:
            print("文件為空")
            return
        
        headers = data[0]
        rows = data[1:]
        
        print(f"文件: {args.file}")
        print(f"行數(shù): {len(rows)} 行(不含表頭)")
        print(f"列數(shù): {len(headers)} 列")
        print(f"列名: {', '.join(headers)}")
        
        # 每列的數(shù)據(jù)類型推測
        if rows:
            print("\n列信息:")
            for i, header in enumerate(headers):
                sample = rows[0][i] if len(rows[0]) > i else ''
                print(f"  {header}: 示例='{sample}'")
    
    def filter_csv(self, args):
        """過濾CSV文件"""
        if not args.filter:
            print("錯誤: 需要指定過濾條件(-f 列名=值)")
            return
        
        # 解析過濾條件
        col_name, value = args.filter.split('=', 1)
        
        with open(args.file, 'r', encoding='utf-8') as infile:
            reader = csv.DictReader(infile)
            headers = reader.fieldnames
            
            # 收集匹配的行
            matching_rows = []
            for row in reader:
                if row.get(col_name) == value:
                    matching_rows.append(row)
        
        # 輸出結果
        if args.output:
            with open(args.output, 'w', encoding='utf-8', newline='') as outfile:
                writer = csv.DictWriter(outfile, fieldnames=headers)
                writer.writeheader()
                writer.writerows(matching_rows)
            print(f"過濾結果已保存到: {args.output} ({len(matching_rows)} 行)")
        else:
            # 打印到控制臺
            writer = csv.DictWriter(sys.stdout, fieldnames=headers)
            writer.writeheader()
            writer.writerows(matching_rows)
    
    def select_columns(self, args):
        """選擇特定列"""
        if not args.columns:
            print("錯誤: 需要指定要選擇的列(-c 列1,列2,...)")
            return
        
        selected = [col.strip() for col in args.columns.split(',')]
        
        with open(args.file, 'r', encoding='utf-8') as infile:
            reader = csv.DictReader(infile)
            
            # 檢查列是否存在
            for col in selected:
                if col not in reader.fieldnames:
                    print(f"警告: 列 '{col}' 不存在")
            
            # 只保留選中的列
            filtered_rows = []
            for row in reader:
                filtered_row = {col: row[col] for col in selected if col in row}
                filtered_rows.append(filtered_row)
        
        # 輸出結果
        if args.output:
            with open(args.output, 'w', encoding='utf-8', newline='') as outfile:
                writer = csv.DictWriter(outfile, fieldnames=selected)
                writer.writeheader()
                writer.writerows(filtered_rows)
            print(f"結果已保存到: {args.output}")
        else:
            writer = csv.DictWriter(sys.stdout, fieldnames=selected)
            writer.writeheader()
            writer.writerows(filtered_rows)
    
    def sample_csv(self, args):
        """隨機抽樣"""
        import random
        
        with open(args.file, 'r', encoding='utf-8') as file:
            reader = csv.reader(file)
            data = list(reader)
        
        if len(data) <= 1:
            print("文件數(shù)據(jù)不足")
            return
        
        headers = data[0]
        rows = data[1:]
        
        # 隨機抽樣
        sample_size = min(args.lines, len(rows))
        sampled_rows = random.sample(rows, sample_size)
        
        # 輸出結果
        output_data = [headers] + sampled_rows
        
        if args.output:
            with open(args.output, 'w', encoding='utf-8', newline='') as file:
                writer = csv.writer(file)
                writer.writerows(output_data)
            print(f"抽樣結果已保存到: {args.output} ({sample_size} 行)")
        else:
            for row in output_data:
                print(', '.join(row))

def create_example_csv():
    """創(chuàng)建示例CSV文件"""
    data = [
        ['id', 'name', 'age', 'city', 'salary'],
        ['1', '張三', '30', '北京', '50000'],
        ['2', '李四', '25', '上海', '45000'],
        ['3', '王五', '35', '廣州', '60000'],
        ['4', '趙六', '28', '深圳', '55000'],
        ['5', '錢七', '32', '杭州', '52000'],
        ['6', '孫八', '29', '南京', '48000'],
        ['7', '周九', '31', '成都', '51000'],
        ['8', '吳十', '27', '武漢', '47000'],
    ]
    
    with open('employees.csv', 'w', encoding='utf-8', newline='') as file:
        writer = csv.writer(file)
        writer.writerows(data)
    
    print("示例文件已創(chuàng)建: employees.csv")

def demo_toolkit():
    """演示工具箱功能"""
    print("=== CSV工具箱功能演示 ===\n")
    
    # 創(chuàng)建示例文件
    create_example_csv()
    
    print("\n1. 查看文件內容:")
    print("-" * 50)
    toolkit = CSVToolkit()
    
    # 模擬命令行參數(shù)
    class Args:
        pass
    
    args = Args()
    args.file = 'employees.csv'
    args.lines = 5
    args.columns = 'name,city,salary'
    args.filter = 'city=北京'
    args.output = None
    
    print("\n2. 顯示前3行:")
    print("-" * 50)
    args.lines = 3
    toolkit.head_csv(args)
    
    print("\n3. 文件統(tǒng)計:")
    print("-" * 50)
    toolkit.csv_stats(args)
    
    print("\n4. 選擇特定列:")
    print("-" * 50)
    toolkit.select_columns(args)
    
    print("\n5. 過濾數(shù)據(jù):")
    print("-" * 50)
    toolkit.filter_csv(args)
    
    print("\n6. 隨機抽樣:")
    print("-" * 50)
    args.lines = 2
    toolkit.sample_csv(args)

if __name__ == "__main__":
    if len(sys.argv) > 1:
        # 命令行模式
        toolkit = CSVToolkit()
        toolkit.run()
    else:
        # 演示模式
        demo_toolkit()
        
        print("\n" + "=" * 50)
        print("使用說明:")
        print("  命令行使用: python csv_toolkit.py <命令> <文件> [選項]")
        print("\n可用命令:")
        for cmd in CSVToolkit().commands:
            print(f"  {cmd}")

四、注意事項

4.1 使用限制

  1. 不適合嵌套數(shù)據(jù):CSV是扁平結構,不適合存儲復雜嵌套數(shù)據(jù)
  2. 類型信息丟失:所有值都是字符串,需要手動轉換類型
  3. 無模式驗證:需要自己驗證數(shù)據(jù)完整性和一致性
  4. 性能限制:對于數(shù)GB的文件,建議使用數(shù)據(jù)庫或專業(yè)工具
  5. 并發(fā)訪問:CSV文件不適合多進程同時讀寫

4.2 常見問題

Q: 讀取CSV時遇到編碼錯誤怎么辦?

A: 按順序嘗試這些編碼:utf-8-siggbkutf-8latin-1

encodings = ['utf-8-sig', 'gbk', 'utf-8', 'latin-1']
for enc in encodings:
    try:
        with open('file.csv', 'r', encoding=enc) as f:
            content = f.read()
        print(f"使用編碼: {enc}")
        break
    except UnicodeDecodeError:
        continue

Q: 數(shù)據(jù)中有逗號,導致列錯位怎么辦?

A: 使用csv.reader而不是手動分割,它會正確處理引號內的逗號。

Q: 文件太大,內存不夠怎么辦?

A: 使用流式處理,一次處理一行:

with open('large.csv', 'r') as file:
    reader = csv.DictReader(file)
    for row in reader:  # 一次只加載一行到內存
        process(row)

Q: 如何跳過CSV文件中的空行?

A: csv.reader會自動跳過完全空白的行,但對于只有空格的行,需要在代碼中處理。

Q: 處理CSV時性能很慢怎么辦?

A: 1. 使用csv.writerows()批量寫入

  1. 考慮使用pandas處理復雜操作
  2. 對于超大數(shù)據(jù),考慮使用數(shù)據(jù)庫

4.3 替代方案

  1. pandas:適合復雜的數(shù)據(jù)分析和處理
  2. 數(shù)據(jù)庫:適合大量數(shù)據(jù)和復雜查詢
  3. Excel/Google Sheets:適合需要手動查看和編輯的場景
  4. JSON/YAML:適合嵌套和結構化數(shù)據(jù)
  5. Parquet/Feather:適合大數(shù)據(jù)和機器學習場景

何時選擇替代方案

  • 需要復雜的數(shù)據(jù)分析和處理 → pandas
  • 數(shù)據(jù)量極大,需要高效查詢 → 數(shù)據(jù)庫
  • 需要多人協(xié)作和手動編輯 → Excel/Google Sheets
  • 數(shù)據(jù)結構復雜,有嵌套 → JSON/YAML
  • 大數(shù)據(jù)和機器學習場景 → Parquet/Feather

五、總結

通過本文的學習,你應該已經(jīng)掌握了:

  • ? csv模塊基礎:如何讀寫各種格式的CSV文件
  • ? 數(shù)據(jù)處理技巧:清洗、轉換、合并、拆分
  • ? 性能優(yōu)化:流式處理、批量操作
  • ? 實戰(zhàn)工具:構建自己的CSV處理工具箱
  • ? 最佳實踐:編碼處理、錯誤處理、性能考慮

csv模塊的核心價值

  1. 簡單直接:處理表格數(shù)據(jù)最直接的方式
  2. 通用性好:幾乎所有系統(tǒng)都支持CSV導入導出
  3. 零成本:Python自帶,無需額外依賴
  4. 透明可控:純文本格式,出現(xiàn)問題容易排查
  5. 生態(tài)豐富:與其他工具鏈完美集成

以上就是Python使用csv模塊進行文件讀寫的操作詳解的詳細內容,更多關于Python csv模塊文件讀寫的資料請關注腳本之家其它相關文章!

相關文章

最新評論

邢台县| 太白县| 嘉祥县| 榆树市| 沐川县| 绥滨县| 万安县| 洛浦县| 长汀县| 泰宁县| 绍兴县| 新泰市| 宝山区| 平武县| 渝中区| 绵阳市| 衡山县| 抚州市| 南宫市| 栾城县| 迁西县| 克拉玛依市| 临洮县| 和林格尔县| 长宁县| 乐平市| 康平县| 西城区| 互助| 晋城| 琼结县| 石门县| 平顺县| 龙川县| 新民市| 万宁市| 巴马| 邻水| 台安县| 乡城县| 琼中|