Python2/Python3通过writerow写入csv文件会有多余的空行 及 bytes和str互相转换

本文探讨了Python中CSV文件写入时遇到的CR,CRLF问题,并提供了Python2和Python3下的解决方案,包括修改文件打开模式、使用特定的dialect以及newline参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Table of Contents

前言

Python2代码

Python2原来代码【有问题的】

现象

问题分析

Python2解决办法​​​​​

Python2完整代码

Tips: 追加写入csv

Python3代码:

方法一:writer加dialect='unix'

方法二:打开方式加newline=''

打印出当前操作系统的换行符

Python3为什么不能以bytes模式打开csv文件?

csv模块writerow函数代码

Python3以bytes模式打开csv文件

福利【重点】:bytes和str互相转换

总结:

文件打开模式


前言

项目需要,先处理txt文档,从中提取数值,然后将其转存为csv档来做数据分析。在存档为csv文件时出问题了,以下为我的经验总结,供各位参考。希望大家可以少走弯路。

Python2代码

Python2原来代码【有问题的】

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import csv

csvRow = ['01:01:00', '33000', '27589', '27070', '27070', '25855']
with open("test.csv","a+") as csvfile:
    writer = csv.writer(csvfile)
    for item in range(0, 3):
        writer.writerow(csvRow)

现象

用Notepad++打开档案(补上这个,怕有些朋友不会View->Show Symbol->Show All Characters ),发现每行末尾都有CR, CRLF,如下截图。

如果用Excel打开,两行中间会多出一空行,如下图:

问题分析

现在就要搞清楚CR, CRLF分别是谁输出的。本文后续会深入分析原因(楼梯在此方法二:打开方式加newline=''

心急的朋友可以先参考这个链接https://bugs.python.org/issue7198

Python2解决办法​​​​​

将文档的打开方式改为二进制方式。

原来的打开方式:with open("test.csv","a+") as csvfile:

更改后打开方式:with open("test.csv","ab+") as csvfile:

Python2完整代码

如下供各位参考:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import csv

csvRow = ['01:01:00', '33000', '27589', '27070', '27070', '25855']
with open("test.csv","ab+") as csvfile:
    writer = csv.writer(csvfile)
    for item in range(0, 3):
        writer.writerow(csvRow)

更新后文件图片,用Notepad++打开如下:

用Excel打开图片如下:

 

Tips: 追加写入csv

将文档的打开方式由w(写入)改为a(追加)方式。

 

Python3代码:

方法一:writerdialect='unix'

headerRow = ['ISN', 'BUILD_PHASE']
oneRow = ['81E2-TESTTEST','PRE-PVT']
with open("test.csv","a+") as csvfile:
    writer = csv.writer(csvfile, dialect='unix')    # 将dialect设置为unix,换行符即为'\n'
    writer.writerow(headerRow)
    writer.writerow(oneRow)

参考csv模块说明,有这么一段话

Readers and writers support a dialect argument, which is a convenient
handle on a group of settings.  When the dialect argument is a string,
it identifies one of the dialects previously registered with the module.
If it is a class or instance, the attributes of the argument are used as
the settings for the reader or writer:

    class excel:
        delimiter = ','
        quotechar = '"'
        escapechar = None
        doublequote = True
        skipinitialspace = False
        lineterminator = '\r\n'
        quoting = QUOTE_MINIMAL

笔者翻译:reader和writer都支持dialect参数,处理一组设置时会很方便。

dialect参数是一个字符串时,它识别为模块先前注册的其中一种方言。

如果它是类或实例,则参数的属性被用来作为reader和writer的设置,如上面的class excel等。

例如,如果dialect参数为excel类时,换行符为\r\n.

如果dialect参数为unix, 换行符为\n【以下可参考csv模块说明文档】

class excel(Dialect):
    """Describe the usual properties of Excel-generated CSV files."""
    delimiter = ','
    quotechar = '"'
    doublequote = True
    skipinitialspace = False
    lineterminator = '\r\n'
    quoting = QUOTE_MINIMAL
register_dialect("excel", excel)

class excel_tab(excel):
    """Describe the usual properties of Excel-generated TAB-delimited files."""
    delimiter = '\t'
register_dialect("excel-tab", excel_tab)

class unix_dialect(Dialect):
    """Describe the usual properties of Unix-generated CSV files."""
    delimiter = ','
    quotechar = '"'
    doublequote = True
    skipinitialspace = False
    lineterminator = '\n'
    quoting = QUOTE_ALL
register_dialect("unix", unix_dialect)

方法二:打开方式加newline=''

headerRow = ['ISN', 'BUILD_PHASE']
oneRow = ['81E2-TESTTEST','PRE-PVT']

# 大家可以将换行符指定为'\n'或'\r'或者不指定,试试效果
with open("test.csv","a+", newline='') as csvfile:  #换行符指定为空字符,不是None【空字符!=None】
    writer = csv.writer(csvfile)
    writer.writerow(headerRow)
    writer.writerow(oneRow)

以下这段话选择builtins.py模块中open函数:

On output, if newline is None, any '\n' characters written are translated to the system default line separator, os.linesep. If newline is '' or '\n', no translation takes place. If newline is any of the other legal values, any '\n' characters written are translated to the given string.

笔者翻译:在输出时,如果换行是None,则写入的任何'\ n'字符都被转换为系统默认行分隔符,os.linesep。 如果换行符是''或'\ n',不进行转换。 如果换行符是任何其他合法值【注意:不能将其随心所意地设置为其他英文字母,大家可以自行实验】,所有'\ n'字符都将被转换为给定的字符串。

如果newline采用默认值None(即不进行指定任何指定),在Windows系统下,os.linesep即为'\r\n',那么此时就会将’\n’转换为’\r\n’(即CRLF),所以会多一个’\r’(回车)出来,如下图。在csv中打开就会多一行。

打印出当前操作系统的换行符

import os
print("os.linesep:%r" %os.linesep)

Python3为什么不能以bytes模式打开csv文件?

有朋友会问:为什么不能像Python2那样,将open方式加个b不就好了吗?

在内置模块builtins.py中open函数中有这么一段话:

Python distinguishes between files opened in binary and text modes,

    even when the underlying operating system doesn't. Files opened in

    binary mode (appending 'b' to the mode argument) return contents as

    bytes objects without any decoding. In text mode (the default, or when

    't' is appended to the mode argument), the contents of the file are

    returned as strings, the bytes having been first decoded using a

platform-dependent encoding or using the specified encoding if given.

笔者翻译过来就是:

Python区分文件的打开方式:二进制模式和文本模式,

即使底层操作系统没有作此区分。 以二进制模式打开的文件

(mode参数要加'b')返回内容为不用解码的bytes对象。

在文本模式下(默认情况,或者mode参数加了't'),文件的内容返回为

string对象--使用操作系统平台的编码或使用指定的编码(如果给定)来将bytes先解码。

简单而言:

Python3有两种表示字符序列的类型:bytes和str。bytes即为原始的8位值,即纯8位值。str包含Unicode字符。

Python3给open函数添加了名为encoding的新参数,其默认值为utf-8,文件的默认打开方式为文本模式。如果像如下这句代码加个b来以二进制打开,那么写入时会提示错误“a bytes-like object is required, not 'str'”,因为writerow写入的是字符串格式【这个可以参考csv模块下的writerow函数代码】。

# Python3为什么不能以bytes模式打开csv文件?【请注意:如下代码执行会出错】
headerRow = ['ISN', 'BUILD_PHASE']
oneRow = ['81E2-TESTTEST','PRE-PVT']

with open("test.csv","ab+") as csvfile: # 打开方式为bytes模式,下面写入会出错
    writer = csv.writer(csvfile)
    writer.writerow(headerRow)
    writer.writerow(oneRow)

csv模块writerow函数代码

【怕某些朋友找不到,贴上csv模块writerow函数代码,注意这句“if isinstance(item, text_type):”判断item是否为text_type。

如果是text_type,才会执行下面encode(编码)语句。如果不是,那就不会被写入csv。

class CSVWriter(CSVBase):
    def __init__(self, fn, **kwargs):
        self.stream = _csv_open(fn, 'w')
        self.writer = csv.writer(self.stream, **self.defaults)

    def writerow(self, row):
        if sys.version_info[0] < 3:
            r = []
            for item in row:
                if isinstance(item, text_type):
                    item = item.encode('utf-8')
                r.append(item)
            row = r
        self.writer.writerow(row)

Python3以bytes模式打开csv文件

# Python3可以以bytes模式打开csv文件
# 只是这时写入的数据格式为bytes,string格式需要利用encode编码为bytes对象
strTest = 'ISN'
with open("test.csv","ab+") as csvfile: # 打开方式为bytes模式
    csvfile.write(os.urandom(10))
    csvfile.write(strTest.encode())

福利【重点】:bytes和str互相转换

之前说了Python3的两种字符表示类型:bytes和str。我们在编写Python程序时,核心部分应该只处理Unicode类型,编码和解码操作应该放在外围。下面的两个辅助函数来自《Effective Python》,个人觉得很好,特分享给大家。

def to_str(bytes_or_str):
    """
    接受str或bytes,总是返回str
    :param bytes_or_str: 
    :return: Instance of str
    """
    if isinstance(bytes_or_str, bytes):
        value = bytes_or_str.decode('utf-8')
    else:
        value = bytes_or_str
    return value    # Instance of str


def to_bytes(bytes_or_str):
    """
    接受str或bytes,总是返回bytes
    :param bytes_or_str: 
    :return: Instance of bytes
    """
    if isinstance(bytes_or_str, str):
        value = bytes_or_str.encode('utf-8')
    else:
        value = bytes_or_str
    return value    # Instance of bytes

总结:

虽然是一个小问题,但是涉及到一些csv基本知识点,以及Python2与Python3的区别。希望各位看官可以明白。

文件打开模式

文件打开模式之间的区别可以参考如下链接:

Python File(文件) 方法_文件打开模式_mode参数

<think>好的,我需要帮助用户将Binetflow文件转换CSV格式。首先,我得确认Binetflow文件是什么。Binetflow通常与网络流量分析相关,可能是某种特定的二进制格式,用来记录网络流数据,比如NetFlow的数据。用户可能想将这些数据转为CSV以便用Excel或其他工具处理。 接下来,用户需要转换的方法。常见的方法可能有使用现有工具或者自己编写脚本。我需要考虑是否有现成的工具,比如nfdump或其他NetFlow处理工具,这些工具是否支持直接输出CSV。或者,可能需要用Python脚本解析二进制文件转换CSV。 考虑到用户可能不熟悉命令行工具,或者希望更灵活的解决方案,编写Python脚本可能是更通用的方法。不过,解析二进制文件需要知道文件格式的结构,这可能比较复杂。如果Binetflow文件的结构是公开的,或者有相关的库可以使用,这会更容易。例如,某些库可能已经实现了对NetFlow数据的解析。 假设用户没有现成的工具,或者需要自定义转换,我可以建议使用Pythonstruct模块来解析二进制数据,然后使用csv模块写入CSV文件。但需要详细说明Binetflow的文件结构,比如每个记录的字段、数据类型、字节顺序等。如果用户不清楚结构,可能需要他们查阅相关文档或提供示例数据。 另外,可能需要检查是否有现有的开源项目或脚本已经实现了这个转换。比如,GitHub上可能有相关项目,或者网络安全社区有分享的工具。如果有的话,推荐用户使用这些现成的解决方案会更节省时间。 如果用户必须自己编写脚本,我需要给出一个基本的框架,包括如何读取二进制文件,解析每个记录,提取字段,然后写入CSV。例如,使用Python打开文件,逐行读取,按照结构解析,然后用csv.writer写入各字段。可能需要处理字节序、字段长度、数据类型转换等问题。 同时,需要提醒用户注意错误处理,比如文件无法打开、解析错误等。另外,大文件处理时可能需要分块读取,避免内存不足。性能方面,可能需要优化代码,比如使用生成器或分批处理。 最后,生成相关问题,帮助用户深入理解,比如如何解析其他网络数据格式、处理大型CSV文件的技巧,或者NetFlow数据的分析应用。</think>### 如何将Binetflow文件转换CSV文件 #### 方法一:使用现成工具(推荐) 1. **NetFlow处理工具** 若文件为NetFlow格式,可使用工具如`nfdump`,通过命令行直接输出CSV: ```bash nfdump -r input.binetflow -o csv > output.csv ``` 此方法需先安装`nfdump`[^2]。 2. **专用转换脚本** 部分开源项目(如GitHub上的`flowtools-reader`)提供Python解析库,可直接读取并转换: ```python from flowtools import read_flow import csv flows = read_flow("input.binetflow") with open("output.csv", "w", newline=&#39;&#39;) as f: writer = csv.writer(f) writer.writerow(["src_ip", "dst_ip", "bytes", "packets"]) # 根据实际字段调整 for flow in flows: writer.writerow([flow.src_ip, flow.dst_ip, flow.bytes, flow.packets]) ``` #### 方法二:自定义Python脚本 若文件格式明确,可手动解析二进制数据: ```python import struct import csv with open("input.binetflow", "rb") as bin_file, open("output.csv", "w", newline=&#39;&#39;) as csv_file: writer = csv.writer(csv_file) writer.writerow(["field1", "field2", "field3"]) # 替换为实际字段名 while True: chunk = bin_file.read(16) # 假设每条记录占16字节 if not chunk: break # 按格式解析,例如:前4字节为源IP(大端序) src_ip = struct.unpack(&#39;>I&#39;, chunk[0:4])[0] # 转换为点分十进制 src_ip_str = ".".join(map(str, [(src_ip >> 24) & 0xFF, (src_ip >> 16) & 0xFF, (src_ip >> 8) & 0xFF, src_ip & 0xFF])) writer.writerow([src_ip_str, ...]) # 补充其他字段 ``` **注意**:需根据具体文件结构调整`struct.unpack`的格式字符串字段偏移量[^3]。 #### 关键注意事项 - **文件格式验证**:需确认Binetflow的具体格式(如字段顺序、编码方式)。 - **性能优化**:大文件建议分块读取,避免内存溢出。 - **错误处理**:添加`try-except`块处理异常数据。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值