我正在使用此代码从外部程序获取标准输出:
>>> from subprocess import *
>>> command_stdout = Popen(['ls', '-l'], stdout=PIPE).communicate()[0]
communic()方法返回一个字节数组:
>>> command_stdout
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2\n'
但是,我想将输出作为普通的Python字符串使用 . 所以我可以这样打印:
>>> print(command_stdout)
-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1
-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2
我认为这是binascii.b2a_qp()方法的用途,但是当我尝试它时,我又得到了相同的字节数组:
>>> binascii.b2a_qp(command_stdout)
b'total 0\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file1\n-rw-rw-r-- 1 thomas thomas 0 Mar 3 07:03 file2\n'
有人知道如何将字节值转换回字符串吗?我的意思是,使用“电池”而不是手动操作 . 而且我希望它能用于Python 3 .
16 回答
从http://docs.python.org/3/library/sys.html起,
要从/向标准流写入或读取二进制数据,请使用基础二进制缓冲区 . 例如,要将字节写入stdout,请使用sys.stdout.buffer.write(b'abc') .
如果你应该通过尝试
decode()
获得以下内容:AttributeError: 'str' object has no attribute 'decode'
您还可以直接在强制转换中指定编码类型:
如果您不知道编码,那么要以Python 3和Python 2兼容的方式将二进制输入读入字符串,请使用古老的MS-DOS cp437编码:
由于编码是未知的,因此期望非英语符号转换为
cp437
的字符(英语字符未翻译,因为它们在大多数单字节编码和UTF-8中匹配) .将任意二进制输入解码为UTF-8是不安全的,因为您可能会得到:
这同样适用于
latin-1
,这对于Python 2很流行(默认?) . 请参阅Codepage Layout中的缺失点 - 这是Python与臭名昭着的ordinal not in range
窒息的地方 .UPDATE 20150604 :有传言称Python 3具有
surrogateescape
错误策略,用于将内容编码为二进制数据而不会丢失数据并导致崩溃,但它需要转换测试[binary] -> [str] -> [binary]
以验证性能和可靠性 .UPDATE 20170116 :感谢Nearoo的评论 - 还有可能使用
backslashreplace
错误处理程序来删除所有未知字节 . 这仅适用于Python 3,因此即使使用此解决方法,您仍将从不同的Python版本获得不一致的输出:有关详细信息,请参阅https://docs.python.org/3/howto/unicode.html#python-s-unicode-support .
UPDATE 20170119 :我决定实现适用于Python 2和Python 3的斜线转义解码 . 它应该比
cp437
解决方案慢,但它应该在每个Python版本上产生 identical results .我觉得这种方式很简单:
您需要解码字节字符串并将其转换为字符(unicode)字符串 .
要么
In Python 3,默认编码为
"utf-8"
,因此您可以直接使用:这相当于
另一方面,in Python 2,编码默认为默认字符串编码 . 因此,你应该使用:
其中
encoding
是您想要的编码 .在Python 2.7中添加了Note:对关键字参数的支持 .
我想你真正想要的是这个:
Aaron的回答是正确的,除了你需要知道要使用的WHICH编码 . 我相信Windows使用'windows-1252' . 只有在你的内容中有一些不寻常的(非ascii)字符才有意义,但它会产生影响 .
顺便说一句,事实上它是重要的是Python转向使用两种不同类型的二进制和文本数据:它不能在它们之间神奇地转换,因为除非你告诉它,它不知道编码!您将知道的唯一方法是阅读Windows文档(或在此处阅读) .
对于Python 3,这是一种更安全的Pythonic方法,可以从
byte
转换为string
:输出:
您需要解码bytes对象以生成字符串:
将universal_newlines设置为True,即
虽然@Aaron Maenpaa's answer正常,但用户recently asked
您可以使用
decode()
有standard argument处理来自Windows系统的数据(带有
\r\n
行结尾)时,我的回答是为什么?尝试使用多行Input.txt:
所有的行结尾都会加倍(到
\r\r\n
),导致额外的空行 . Python的文本读取函数通常将行结尾标准化,以便字符串仅使用\n
. 如果从Windows系统接收二进制数据,Python就没有机会这样做 . 从而,将复制您的原始文件 .
我做了一个清理列表的功能
要将字节序列解释为文本,您必须知道相应的字符编码:
例:
ls
命令可能会生成无法解释为文本的输出 . Unix上的文件名可以是除了斜杠b'/'
和零b'\0'
之外的任何字节序列:尝试使用utf-8编码解码这样的字节汤会引发
UnicodeDecodeError
.可能会更糟 . 如果您使用,解码可能会无声地失败并产生mojibake错误的不兼容编码:
数据已损坏,但您的程序仍未发现故障已发生 .
通常,要使用的字符编码不嵌入字节序列本身 . 您必须在带外传达此信息 . 某些结果比其他结果更可能,因此存在可以猜测字符编码的模块 . 单个Python脚本可能在不同的位置使用多个字符编码 .
可以使用
os.fsdecode()
函数将ls
输出转换为Python字符串,即使对于undecodable filenames也是如此(它在Unix上使用sys.getfilesystemencoding()
和surrogateescape
错误处理程序):要获取原始字节,可以使用
os.fsencode()
.如果传递
universal_newlines=True
参数,则subprocess
使用locale.getpreferredencoding(False)
来解码字节,例如,它可以是Windows上的cp1252
.要即时解码字节流,可以使用io.TextIOWrapper():example .
不同的命令可以对其输出使用不同的字符编码,例如,
dir
内部命令(cmd
)可以使用cp437 . 要解码其输出,您可以显式传递编码(Python 3.6):文件名可能与
os.listdir()
(使用Windows Unicode API)不同,例如,'\xb6'
可以用'\x14'
-Python的cp437编解码器映射b'\x14'
代替,以控制字符U 0014而不是U 00B6(¶) . 要支持具有任意Unicode字符的文件名,请参阅Decode poweshell output possibly containing non-ascii unicode characters into a python string由于这个问题实际上是在询问
subprocess
输出,因此您可以使用更直接的方法,因为Popen
接受encoding关键字(在Python 3.6中):其他用户的一般答案是将字节解码为文本:
没有参数,将使用sys.getdefaultencoding() . 如果您的数据不是
sys.getdefaultencoding()
,则必须在decode调用中明确指定编码: