Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么将logger encoding设置为UTF-8以UNIX行结尾写入文件?_Python_Python 2.7_Logging_Utf 8_Newline - Fatal编程技术网

Python 为什么将logger encoding设置为UTF-8以UNIX行结尾写入文件?

Python 为什么将logger encoding设置为UTF-8以UNIX行结尾写入文件?,python,python-2.7,logging,utf-8,newline,Python,Python 2.7,Logging,Utf 8,Newline,我创建了一个写入文本文件的记录器: 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 th

我创建了一个写入文本文件的记录器:

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.")
问题在于,尽管我在Windows 7(64位)上运行此程序,但写入的日志文件debug.log使用了单个换行符(LF)作为换行符:

奇怪的是,如果我改为在没有
encoding='utf-8'
参数的情况下设置记录器的文件句柄,则换行符正确地写为CR/LF


为什么将编码设置为UTF-8会导致Python使用不正确的换行符?

当您指定编码时,使用的是而不是常规的
open()
调用。此函数始终以二进制模式打开文件,并在此基础上实现编码。这样,它可以保证任何编解码器都能工作,而不仅仅是基于ASCII的编解码器。这种选择的一个副作用是,在Windows上,新行不再转换为平台约定

你可以提交一个bug来修复它,更好的解决方案是使用;
io
模块是新的Python3I/O框架,后端口到Python2,它可以更好地处理文本模式,包括在Windows上正确处理换行符

您可以修补
logging.FileHandler.\u 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对象。

感谢您提供了上述和其他答案。我不喜欢重写stdlib类的方法(同样是私有方法!),我认为UTF-8不值得这么做,但我相信这个答案会帮助人们。可能很快就会提交一个bug…有点离题,但您知道在Unix服务器上写入这样的日志文件时如何强制CRLF的行尾吗?@Alexis.Rolland:add
newline='\r\n'
io.open()
调用打补丁的
FileHandler.\u 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