python输入,输出,文件描述符相关

前言

我们在写程序的时候经常会用到输入,输出,python 对用户输入和输出也提供了很好的支持,如 print 函数很好的支持了输出,raw_input 支持输入,但是在一些更复杂的场景,这两个函数没法满足我们的需求,我们就需要了解底层的标准输入,标准输出,标准错误,对应 python 中 sys 模块里的 sys.stdoutsys.stdinsys.stderr,以及系统底层的文件描述符 fileno,这就是我们今天需要介绍的内容

由浅入深之标准模块输入输出

实际上标准输入,标准输出,标准错误是内建在每一个 UNIX 系统中的管道,在 python 程序中我们调用 print 函数实际上就是间接调用的 sys.stdout.write() 函数,当调用 raw_input()就是间接的调用 sys.stdin.readline() 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# coding=utf-8
import os
import sys

print("这是一个测试")
sys.stdout.write("这是一个测试\n")
print 1

name_1 = raw_input("请输入你的名字1:")
print name_1, len(name_1)

sys.stdout.write("请输入你的名字2:")
name_2 = sys.stdin.readline().strip()
print name_2, len(name_2)

输出结果如下

1
2
3
4
5
6
7
8
这是一个测试
这是一个测试
1
请输入你的名字1:123
123 3
请输入你的名字2:457
457
4

区别在于 print 函数默认会加上一个 \n 的换行符,sys.stdin.readline() 函数也会多读进来一个 \n 换行符,我们可以用 strip 函数或者 \n 换行符来处理,这样达到的效果是 print 函数和 raw_input 函数都可以用 sys.stdint.readline 函数来替代

文件描述符

python 中文件对象都有一个 fileno 方法,fileno 方法返回操作系统I/O操作的文件描述符(可理解为是第几个打开的文件),一般打开的第一个文件编号是3,前3个(0-2)为三个标准输出流,stdin,stdout,stderr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> import sys
>>> sys.stdin.fileno()
0
>>> sys.stdout.fileno()
1
>>> sys.stderr.fileno()
2
>>> sys.stdin
<open file '<stdin>', mode 'r' at 0x10d4920c0>
>>> f = open("test.txt", "w")
>>> f.fileno()
3
>>> f
<open file '123.txt', mode 'w' at 0x10d6006f0>

其中的对象 f 和系统 sys 模块中的标准输入,输出 sys.stdin 是同一类文件对象,那是不是可以考虑用引用赋值来做重定向了?

标准输入,输出,错误-重定向

在系统里面我们经常用 > 或者 >> 来做重定向,实际上就是把程序的输出结果 stdout 重定向到某个文件或地方,在程序里面我们也可用系统内建模块 sys 来做相关操作,效果非常赞

重定向到文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# coding=utf-8
import os
import sys

redirect_file_handler = open("result.txt", "w")
temp = sys.stdout
sys.stdout = redirect_file_handler
print 123
redirect_file_handler.close()

sys.stdout = temp
print 456

with open("result.txt", "r") as file:
ret = file.readline()
print ret, len(ret)

输出结果:

1
2
3
4
456
123
4
[Finished in 0.0s]

通过输出的顺序我们看到,123并没有直接在屏幕进行输出,而是被重定向到了 result.txt 文件,等我们重置重定向后,通过 print 函数才可以输出 456

终端,文件自定义重定向输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# coding=utf-8
import os
import sys

class RedirectObject(object):
def __init__(self, file_path):
self.__buff__ = ""
self.stdout = sys.stdout
self.file_path = file_path

def write(self, value):
self.__buff__ += value

def to_console(self):
sys.stdout = self.stdout
print self.__buff__

def to_files(self):
file_handler = open(self.file_path, "w")
sys.stdout = file_handler
print self.__buff__
file_handler.close()

def flush(self):
self.__buff__ = ""

def reset(self):
self.__buff__ = ""
sys.stdout = self.stdout

redirect_obj = RedirectObject("redirect_result.txt")
redirect_obj.write("123\n")
redirect_obj.write("456\n")
redirect_obj.to_console()
redirect_obj.to_files()

这段代码很有意思,可以在终端和文件中自定义输出,默认数据会存到 __buff__ 缓存中,根据需要把缓存刷到终端或者文件

坚持原创技术分享,您的支持将鼓励我继续创作!