rabbitfoot530's diary

読んだ本と、プログラムに関することのメモです。好きな言語は、C++, Python, Golang, TypeScript。数学・物理・学習理論も好きです。

PythonによるLinuxプログラミングインタフェース(4章 copy)

 4章P75のファイルをopenしてread、readした内容をwriteしてファイルをコピーするというプログラム。

pythonで書くと下記。

#/usr/bin/env
#-*- encoding: utf-8 -*-
import sys


def usage_error(filename):
    print("{0} old-file new-file".format(filename))

def error_exit(str):
    print("error: " + str)
    exit()

def unix_like():
    import os
    import stat

    BUF_SIZE = 1024

    argc = len(sys.argv)
    if argc != 3 or sys.argv[1] == "--help":
        usage_error(sys.argv[0])

    input_fd = os.open(sys.argv[1], os.O_RDONLY)
    if input_fd == -1:
        os.close(input_fd)
    open_flags = os.O_CREAT | os.O_WRONLY | os.O_TRUNC;
    file_perms = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | stat.S_IWOTH;

    output_fd = os.open(sys.argv[2], open_flags, file_perms)
    if output_fd == -1:
        os.close(output_fd)

    while True:
        buffer = os.read(input_fd, BUF_SIZE)
        if not buffer:
            break
        os.write(output_fd, buffer)

    if os.close(input_fd) == -1:
        error_exit("close input")

    if os.close(output_fd) == -1:
        error_exit("close output")


def pythonic():
    argc = len(sys.argv)
    if argc != 3 or sys.argv[1] == "--help":
        usage_error(sys.argv[0])

    # Open input and output files
    try:
        file = open(sys.argv[1], encoding='utf-8')
    except IOError as e:
        print("opening file {0}".format(e.strerror))
        exit()
    else:
        try:
            lines = file.readlines()
        finally:
            file.close()

    try:
        out_file = open(sys.argv[2], "w")
    except IOError as e:
        print("opening file {0}".format(e.strerror))
        quit()
    else:
        [out_file.write(line) for line in lines]
    finally:
        out_file.close()

       # [Using python “with” statement with try-except block](http://bit.ly/1cQ3hcK)

# ./p75_copy.py p75_copy.py p75_copy_w.txt
if __name__ == '__main__':
    pythonic()
    unix_like()

Cだとexit()を読んでるけど、pythonだとquitとexitがあって、どうやら中身の実装は同じ模様。

difference between quit and exit in python

あと、Cだと当然、ファイルが開けたかどうかをファイルディスクリプタを見て判定するけど、pythonでも同じようにファイルが開けたかどうかを判定するには、1回tryでopenをして判定するのがよさそう。

けど、pythonだと下記のwithを使った構文がある。。。

with open(path) as file:

けど、withを使った構文では、ファイルが開けたかどうかをキャッチする方法が用意されてない。 なので、下記のようにtryで囲むのかと思ったが...

try:
    with open(path) as file:

どうやら、このwithをtryで囲む方法は、newbieがやりがちだが良くないと書かれている。。。

となると、先にpathlibでファイルの有りかを調べてから、withでopenすれば良いのかという案が下記。

def pythonic2():
    import pathlib

    argc = len(sys.argv)
    if argc != 3 or sys.argv[1] == "--help":
        usage_error(sys.argv[0])

    # Open input and output files
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    if pathlib.Path(input_file).is_file():
        with open(input_file, encoding='utf-8') as rfile, open(output_file, 'w', encoding='utf-8') as wfile:
            try:
                lines = rfile.readlines()
                [wfile.write(line) for line in lines]
            except Exception as e:
                print("err: {0}".format(e))

# ./p75_copy.py p75_copy.py p75_copy_w.txt
if __name__ == '__main__':
    pythonic2()