Python CSV追加操作后主记录单值字段双引号丢失异常排查
CSV主记录文件追加更新时单值字段双引号丢失异常排查
项目逻辑背景
项目由两个Python模块组成:
- 第一模块负责对比两份CSV文件(Master Records主记录、Latest Records最新记录,两份文件均存储带指定属性的对象数据),提取两份文件的增量差异,调用第二模块通过API在Web服务器上执行对象的创建、修改、删除操作。
- 第二模块基于Python requests库实现与Web服务器的API交互,根据单条记录的实际执行结果,对主记录CSV文件执行新增、修改、删除更新。
- 流程执行完成后,第一模块会在终端打印增量对象记录及对应执行操作,输出格式示例如下:
+----+-----------+---------------+----------------+------------+----------+--------------------------------------+--------------------------------------------+ | | UE_NAME | UE_TYPE | ES_NAME | APN_NAME | STATUS | UE_ROUTES_OPERATION(MOBILE_ROUTER) | UE_ROUTES(MOBILE_ROUTER) | +====+===========+===============+================+============+==========+======================================+============================================+ | 0 | ue_1 | MOBILE_ROUTER | Edge_service_4 | apn1862 | UE_ADDED | UE_ROUTE_ADDED | ['172.16.10.0/26(A)'] | +----+-----------+---------------+----------------+------------+----------+--------------------------------------+--------------------------------------------+ | 1 | ue_6 | IOT_MOBILE | Edge_service_1 | apn_nuage | UE_ADDED | -- | -- | +----+-----------+---------------+----------------+------------+----------+--------------------------------------+--------------------------------------------+ | 2 | ue_2 | MOBILE_ROUTER | Edge_service_4 | apn1862 | UE_ADDED | UE_ROUTE_ADDED | ['172.16.10.0/18(A)', '172.16.12.0/24(A)'] | +----+-----------+---------------+----------------+------------+----------+--------------------------------------+--------------------------------------------+ | 3 | ue_201 | MOBILE_ROUTER | Edge_service_4 | apn_nuage | UE_ADDED | UE_ROUTE_ADDED | ['172.16.10.0/16 (A)'] | +----+-----------+---------------+----------------+------------+----------+--------------------------------------+--------------------------------------------+
问题现象
代码逻辑整体运行正常,但主记录文件的追加更新存在格式异常:
- 首次执行工具后,生成的master_records.csv格式正常,包含多个路由值的ueRoutes字段被双引号正确包裹
- 修改Latest_records.csv中的某条条目(例如ue_1)后重新执行脚本,未被修改的ue_201条目中仅包含单个路由值的ueRoutes字段双引号意外丢失,多值字段的双引号仍正常保留
两次执行后的文件内容对比如下:
首次执行后文件内容:
more .\master_records.csv name,IMSI,MSISDN,ICCID,IMEI,Enterprise,operationalStatus,ueType,ueRoutes,description,apn_name ue_1,1,1,1,1,Edge_service_4,IDLE,MOBILE_ROUTER,"172.16.10.0/26",UE-1-desc,apn1862 ue_6,6,6,6,6,Edge_service_1,CONNECTED,IOT_MOBILE,,UE-6,apn_nuage ue_2,2,2,2,2,Edge_service_4,CONNECTED,MOBILE_ROUTER,"172.16.10.0/18,172.16.12.0/24",UE-2-desc,apn1862 ue_201,201,201,201,203,test1,IDLE,MOBILE_ROUTER,"172.16.10.0/16 ",UE-201,apn_nuage
二次执行修改ue_1后文件内容:
more .\master_records.csv name,IMSI,MSISDN,ICCID,IMEI,Enterprise,operationalStatus,ueType,ueRoutes,description,apn_name ue_6,6,6,6,6,Edge_service_1,CONNECTED,IOT_MOBILE,,UE-6,apn_nuage ue_2,2,2,2,2,Edge_service_4,CONNECTED,MOBILE_ROUTER,"172.16.10.0/18,172.16.12.0/24",UE-2-desc,apn1862 ue_201,201,201,201,203,test1,IDLE,MOBILE_ROUTER,172.16.10.0/16 ,UE-201,apn_nuage ue_1,1,1,1,1,Edge_service_4,CONNECTED,MOBILE_ROUTER,"172.16.10.0/26",UE-1-desc,apn1862
关联代码逻辑
主记录追加写入代码:
def add_entry_master_record(row_entry): """ Adds a UE Entry to Master Record file. :param row_entry: UE record Entry. :return: Updates the existing Master Record file. """ try: with open(m_record, 'a+') as master_record_update: master_record_update.write(row_entry) master_record_update.write('\n') except FileNotFoundError as err_file: raise SystemExit(err_file)
触发更新时传入的row_entry仅包含待更新的ue_1条目内容,未对ue_201执行任何写入操作:
row_entry = ue_1,1,1,1,1,Edge_service_4,CONNECTED,MOBILE_ROUTER,"172.16.10.0/26",UE-1-desc,apn1862
修改现有对象时,会先通过pandas读取CSV、过滤删除待修改对象的旧记录、重写文件后,再调用上述追加函数写入更新后的条目,删除旧记录的代码如下:
def drop_rows_master_record(ue_name, mod_entry): """ Drops the Entries from Master Record csv file. :param ue_name: UE Name for which Entry needs to be dropped. :param mod_entry: UE Record :return: Drops the deleted/modified UE record from Master Records. """ df = pd.read_csv(m_record) df_filtered = df[(df['name'].str.lower() == ue_name.lower()) & (df['Enterprise'].str.lower() == mod_entry['Enterprise'].lower())] df.drop(df_filtered.index, inplace=True) df.reset_index(drop=True, inplace=True) df.to_csv(m_record, index=False)
该格式异常会导致后续主记录与最新记录的增量计算逻辑误将无变更内容识别为增量,目前已通过对比前增加正则替换的方式做了临时规避,需要定位异常出现的根本原因。
根本原因
异常和追加写入操作无关,核心问题是混用了两套CSV写入规则,引用转义逻辑不统一:
- pandas读取CSV时,会自动解析双引号包裹的字段,将引号去除后存入DataFrame,不会保留原始文件中的双引号标记。
- pandas的
to_csv()方法默认采用最小必要转义规则:仅当字段值包含CSV分隔符(即逗号)时,才会自动给字段包裹双引号;如果字段值不含逗号,就直接写入原值,不添加额外引号。 - 首次生成master_records.csv时,所有条目都是通过手动拼接带双引号的字符串写入的,因此单值、多值的ueRoutes字段都带双引号。
- 修改条目调用
drop_rows_master_record时,pandas会重写整个文件:多值路由字段因为值本身包含逗号,pandas会自动添加双引号,和原格式一致;单值路由字段不含逗号,pandas不会主动加双引号,直接写入原值,这就是ue_201这类单值条目双引号丢失的原因。 - 后续通过
add_entry_master_record追加的ue_1条目是手动拼接的带双引号字符串,因此追加的条目保留了双引号,和pandas重写的内容格式不一致。
修复指引
- 停止混用pandas读写和手动字符串拼接写入的逻辑,全程采用同一套CSV处理规则,避免转义逻辑不统一:
- 方案1:全程使用pandas处理CSV读写,追加条目时将新记录转为DataFrame和原有数据拼接后,统一调用
to_csv()写入。如果需要固定给ueRoutes字段添加双引号,可以在to_csv()时传入quoting=csv.QUOTE_NONNUMERIC参数,给所有非数值字段统一添加引号。 - 方案2:全程使用Python标准库
csv模块处理文件读写,不通过pandas重写整份文件,保证读写时的字段引用规则一致。
- 方案1:全程使用pandas处理CSV读写,追加条目时将新记录转为DataFrame和原有数据拼接后,统一调用
- 正则替换的临时方案无法覆盖字段值包含引号、换行符等边界场景,不建议长期使用。
内容的提问来源于stack exchange,提问作者Rahul Tyagi
相关产品推荐
相关产品推荐

