python在Windows命令行窗口(cmd)实现utf8编码中文输入输出

执行以下函数后即可实现中文输入输出
#-*- coding: utf-8 -*-


def utf8writer_register():
    import sys

    if sys.platform == "win32":
        import codecs
        from ctypes import WINFUNCTYPE, windll, POINTER, byref, c_int
        from ctypes.wintypes import BOOL, HANDLE, DWORD, LPWSTR, LPCWSTR, LPVOID

        original_stderr = sys.stderr

        # If any exception occurs in this code, we'll probably try to print it on stderr,
        # which makes for frustrating debugging if stderr is directed to our wrapper.
        # So be paranoid about catching errors and reporting them to original_stderr,
        # so that we can at least see them.
        def _complain(message):
            print >> original_stderr, message if isinstance(message, str) else repr(message)

        # Work around <http://bugs.python.org/issue6058>.
        codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None)

        # Make Unicode console output work independently of the current code page.
        # This also fixes <http://bugs.python.org/issue1602>.
        # Credit to Michael Kaplan <http://blogs.msdn.com/b/michkap/archive/2010/04/07/9989346.aspx>
        # and TZOmegaTZIOY
        # <http://stackoverflow.com/questions/878972/windows-cmd-encoding-change-causes-python-crash/1432462#1432462>.
        try:
            # <http://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx>
            # HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
            # returns INVALID_HANDLE_VALUE, NULL, or a valid handle
            #
            # <http://msdn.microsoft.com/en-us/library/aa364960(VS.85).aspx>
            # DWORD WINAPI GetFileType(DWORD hFile);
            #
            # <http://msdn.microsoft.com/en-us/library/ms683167(VS.85).aspx>
            # BOOL WINAPI GetConsoleMode(HANDLE hConsole, LPDWORD lpMode);

            GetStdHandle = WINFUNCTYPE(HANDLE, DWORD)(("GetStdHandle", windll.kernel32))
            STD_INPUT_HANDLE = DWORD(-10)
            STD_OUTPUT_HANDLE = DWORD(-11)
            STD_ERROR_HANDLE = DWORD(-12)
            GetFileType = WINFUNCTYPE(DWORD, DWORD)(("GetFileType", windll.kernel32))
            FILE_TYPE_CHAR = 0x0002
            FILE_TYPE_REMOTE = 0x8000
            GetConsoleMode = WINFUNCTYPE(BOOL, HANDLE, POINTER(DWORD))(("GetConsoleMode", windll.kernel32))
            INVALID_HANDLE_VALUE = DWORD(-1).value

            def not_a_console(handle):
                if handle == INVALID_HANDLE_VALUE or handle is None:
                    return True
                return ((GetFileType(handle) & ~FILE_TYPE_REMOTE) != FILE_TYPE_CHAR
                        or GetConsoleMode(handle, byref(DWORD())) == 0)
            # old_stdin_fileno  = None
            old_stdout_fileno = None
            old_stderr_fileno = None
            # if hasattr(sys.stdin, 'fileno'):
            #     old_stdin_fileno = sys.stdin.fileno()
            if hasattr(sys.stdout, 'fileno'):
                old_stdout_fileno = sys.stdout.fileno()
            if hasattr(sys.stderr, 'fileno'):
                old_stderr_fileno = sys.stderr.fileno()
            # STDIN_FILENO  = 0
            STDOUT_FILENO = 1
            STDERR_FILENO = 2
            # real_stdin  = (old_stdin_fileno  == STDIN_FILENO)
            real_stdout = (old_stdout_fileno == STDOUT_FILENO)
            real_stderr = (old_stderr_fileno == STDERR_FILENO)

            # if real_stdin:
            #     hStdin = GetStdHandle(STD_INPUT_HANDLE)
            #     if not_a_console(hStdin):
            #         real_stdin = False

            if real_stdout:
                hStdout = GetStdHandle(STD_OUTPUT_HANDLE)
                if not_a_console(hStdout):
                    real_stdout = False

            if real_stderr:
                hStderr = GetStdHandle(STD_ERROR_HANDLE)
                if not_a_console(hStderr):
                    real_stderr = False

            if real_stdout or real_stderr: # or real_stdin
                # BOOL WINAPI WriteConsoleW(HANDLE hOutput, LPWSTR lpBuffer, DWORD nChars,
                #                           LPDWORD lpCharsWritten, LPVOID lpReserved);

                WriteConsoleW = WINFUNCTYPE(BOOL, HANDLE, LPWSTR, DWORD, POINTER(DWORD), LPVOID)(
                    ("WriteConsoleW", windll.kernel32))

                class UnicodeOutput:
                    def __init__(self, hConsole, stream, fileno, name):
                        self._hConsole = hConsole
                        self._stream = stream
                        self._fileno = fileno
                        self.closed = False
                        self.softspace = False
                        self.mode = 'w'
                        self.encoding = 'utf-8'
                        self.name = name
                        self.flush()

                    def isatty(self):
                        return False

                    def close(self):
                        # don't really close the handle, that would only cause problems
                        self.closed = True

                    def fileno(self):
                        return self._fileno

                    def flush(self):
                        if self._hConsole is None:
                            try:
                                self._stream.flush()
                            except Exception as e:
                                _complain("%s.flush: %r from %r" % (self.name, e, self._stream))
                                raise

                    def write(self, text):
                        try:
                            if self._hConsole is None:
                                if isinstance(text, unicode):
                                    text = text.encode('utf-8')
                                self._stream.write(text)
                            else:
                                if not isinstance(text, unicode):
                                    text = str(text).decode('utf-8')
                                remaining = len(text)
                                while remaining:
                                    n = DWORD(0)
                                    # There is a shorter-than-documented limitation on the
                                    # length of the string passed to WriteConsoleW (see
                                    # <http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232>.
                                    retval = WriteConsoleW(self._hConsole, text, min(remaining, 10000), byref(n), None)
                                    if retval == 0 or n.value == 0:
                                        raise IOError("WriteConsoleW returned %r, n.value = %r" % (retval, n.value))
                                    remaining -= n.value
                                    if not remaining:
                                        break
                                    text = text[n.value:]
                        except Exception as e:
                            _complain("%s.write: %r" % (self.name, e))
                            raise

                    def writelines(self, lines):
                        try:
                            for line in lines:
                                self.write(line)
                        except Exception as e:
                            _complain("%s.writelines: %r" % (self.name, e))
                            raise

                    def read(self, n=1):
                        return unicode(self._stream.read(n), self._stream.encoding)

                    def readinto(self, b):
                        return unicode(self._stream.readinto(b), self._stream.encoding)

                    def readline(self, limit=-1):
                        return unicode(self._stream.readline(limit), self._stream.encoding)

                    def readlines(self, limit=-1):
                        result = [unicode(s, self._stream.encoding) for s in self._stream.readlines(limit)]
                        return result

                #if real_stdin:
                    #sys.stdin = UnicodeOutput(hStdin, None, STDIN_FILENO, '<Unicode console stdin>')
                #else:

                # It is more difficult to read from hStdin than write to hStdout,
                # cause bottom line fully work for me,
                # I haven't implemented it with win32api(ReadConsole).
                sys.stdin = UnicodeOutput(None, sys.stdin, sys.stdin.fileno(), '<Unicode redirected stdin>')

                if real_stdout:
                    sys.stdout = UnicodeOutput(hStdout, None, STDOUT_FILENO, '<Unicode console stdout>')
                else:
                    sys.stdout = UnicodeOutput(None, sys.stdout, old_stdout_fileno, '<Unicode redirected stdout>')

                if real_stderr:
                    sys.stderr = UnicodeOutput(hStderr, None, STDERR_FILENO, '<Unicode console stderr>')
                else:
                    sys.stderr = UnicodeOutput(None, sys.stderr, old_stderr_fileno, '<Unicode redirected stderr>')


        except Exception as e:
            _complain("exception %r while fixing up sys.stdout and sys.stderr" % (e,))


        # While we're at it, let's unmangle the command-line arguments:

        # This works around <http://bugs.python.org/issue2128>.
        GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32))
        CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))(
            ("CommandLineToArgvW", windll.shell32))

        argc = c_int(0)
        argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc))

        argv = [argv_unicode[i].encode('utf-8') for i in xrange(0, argc.value)]

        if not hasattr(sys, 'frozen'):
            # If this is an executable produced by py2exe or bbfreeze, then it will
            # have been invoked directly. Otherwise, unicode_argv[0] is the Python
            # interpreter, so skip that.
            argv = argv[1:]

            # Also skip option arguments to the Python interpreter.
            while len(argv) > 0:
                arg = argv[0]
                if not arg.startswith(u"-") or arg == u"-":
                    break
                argv = argv[1:]
                if arg == u'-m':
                    # sys.argv[0] should really be the absolute path of the module source,
                    # but never mind
                    break
                if arg == u'-c':
                    argv[0] = u'-c'
                    break

        # if you like:
        sys.argv = argv

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值