簡體   English   中英

為什么將記錄器編碼設置為UTF-8會將文件寫入UNIX行尾?

[英]Why setting logger encoding to UTF-8 writes file with UNIX line-endings?

我創建了一個寫入文本文件的記錄器:

import logging

logger_dbg = logging.getLogger("dbg")
logger_dbg.setLevel(logging.DEBUG)
fh_dbg_log = logging.FileHandler('debug.log', mode='w', encoding='utf-8')
fh_dbg_log.setLevel(logging.DEBUG)

# Print time, logger-level and the call's location in a source file.
formatter = logging.Formatter(
    '%(asctime)s-%(levelname)s(%(module)s:%(lineno)d)  %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S')
fh_dbg_log.setFormatter(formatter)

logger_dbg.addHandler(fh_dbg_log)
logger_dbg.propagate = False

然后,當我想記錄一些信息時,我稱之為記錄器:

logger_dbg.debug("Closing port...")
logger_dbg.debug("Port closed.")

問題是寫入的日志文件debug.log使用單個換行(LF)字符作為換行符,盡管我在Windows 7(64位)上運行此程序:

2015-11-30 12:39:08-DEBUG(SerialThread:196)  Closing port...  2015-11-30 12:39:08-DEBUG(SerialThread:198)  Port closed.

奇怪的是,如果我在沒有encoding='utf-8'參數的情況下設置記錄器的文件句柄,則換行字符被正確寫為CR / LF。

為什么將編碼設置為UTF-8會導致Python使用不正確的換行符?

指定編碼時,使用codecs.open()而不是常規的open()調用。 此函數始終以二進制模式打開文件,並在其上實現編碼。 這樣它可以保證任何編解碼器都能工作,而不僅僅是基於ASCII的編解碼器。 這種選擇的副作用是Windows上的換行符不再轉換為平台約定!

您可以提交一個錯誤來修復此問題,更好的解決方案是使用io.open() ; io模塊是新的Python 3 I / O框架,向后移植到Python 2,它更好地處理文本模式,包括在Windows上正確處理換行。

您可以修補logging.FileHandler._open方法以在本地修復此問題:

import io
from logging import FileHandler

_orig_open = FileHandler._open
_orig_emit = FileHandler.emit

def filehandler_open_patch(self):
    if self.encoding is not None:
        return io.open(self.baseFilename, self.mode, encoding=self.encoding)
    return _orig_open(self)

def filehandler_emit_patch(self, record):
    if not self.encoding:
        return _orig_emit(self, record)
    try:
        msg = self.format(record)
        stream = self.stream
        fs = u"%s\n"
        if not isinstance(msg, unicode):
            msg = msg.decode('ASCII', 'replace')
        ufs = u'%s\n'
        stream.write(ufs % msg)
        self.flush()
    except (KeyboardInterrupt, SystemExit):
        raise
    except:
        self.handleError(record)

FileHandler._open = filehandler_open_patch
FileHandler.emit = filehandler_emit_patch

FileHandler.emit()方法也需要打補丁,否則Unicode消息首先被編碼為UTF-8,但io.open()文件對象只接受Unicode對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM