李成石

导航

 

    闲来无事,在github上发现一个很有趣的project crudini,实现命令行对ini文件的增删改查和merge操作。起初会觉得至于如此小题大做么,但查阅之后,发现该项目对文件的操作比较精细,从文件锁FileLock、临时文件tempfile、SHA256 hashlib、退出执行atexit、shutil文件操作都使人眼前一亮。工程地址:https://github.com/joehakimrahme/crudini

contextlib上下文管理器

  使用装饰器 contextlib.contextmanager() 将一个生成器函数转换为上下文管理器,在yield前,为前置操作,在__enter__中执行,yield为后置操作,在__exit__执行

举个例子:

import contextlib
import os

@contextlib.contextmanager
def remove_file_on_error(path):
    try:
        print("befor yield...")
        yield
        print("after yield....")
    except Exception as e:
        if os.path.exists(path):
            os.unlink(path)

with remove_file_on_error('caesar'):
    # some file operation
    print("d")

    在contextlib库的GeneratorContextManager中定义被装饰的方法,在__enter__时,调用生成器的next方法(self.gen.next),所以会执行yield前面的操作。在yield返回None之后,__enter__执行完毕。

开始调用上下文的Body,即例子中的print("d")。调用完成后,继续调用GeneratorContextManager的__exit___方法(self.gen.next)执行yield的后面部分,完成后抛出StopIteration异常结束。

在contextlib库中 contextmanager 中对GeneratorContextManager进行调用,形成装饰器,可以很方便实现上下文管理,更重要的是在方法前、方法后、异常中进行操作。

在curlini中使用如下,对文件操作的上下文管理(创建临时文件、权限fchown修改,data写入、rename临时文件),如果出现异常,则删除临时文件

python中os操作

os.unlink(filepath)  删除filepath文件

f=os.fileno() 获取文件对象,返回一个int数字,叫做文件描述符

os.write(f, data) 向f 对象中写入data,os.flush()刷入文件, os.fsysn(f) 强制将文件描述符为f的文件刷入硬盘

sys.stdin.read() 从输入流中读取数据,特别适合shell中使用"<" 流入的情况

创建临时文件tempfile模块,在当前文件夹下创建一个"name.字符串.tmp" 的文件,文件为空

(f, tmp) = tempfile.mkstemp(".tmp", prefix=name + ".", dir=".")

文件锁

在linux系统/proc/locks 下:

第一列表示锁的类型,FLOCK和POSIX,第二列是建议性锁(不具备强制性。一个进程使用flock将文件锁住,另一个进程可以直接操作正在被锁的文件,修改文件中的数据,原因在于flock只是用于检测文件是否被加锁,针对文件已经被加锁,另一个进程写入数据的情况,内核不会阻止这个进程的写入操作,是建议性锁的内核处理策略。在这种情况,使用vim依然可以编辑文件,只对存在锁检查的进程进行阻塞。第四列表示使用这个锁的进程。

如下:进程2223获取锁在执行操作,进程2279在等待,直到2223释放锁。

在curlini中分别对windows和linux下的锁进行lock和unlock方法进行定义,如下:

import os

class FileLock(object):
    """Advisory file based locking.  This should be reasonably cross platform
       and also work over distributed file systems."""
    def __init__(self, fno, exclusive=False):
        # fno is FileObject
        self.fp = fno
        self.locked = False

        if os.name == 'nt':
            import msvcrt

            def lock(self):
                msvcrt.locking(self.fp, msvcrt.LK_LOCK, 1)
                self.locked = True

            def unlock(self):
                if self.locked:
                    msvcrt.locking(self.fp, msvcrt.LK_UNLCK, 1)
                self.locked = False

        else:
            import fcntl

            def lock(self):
                operation = fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH
                fcntl.lockf(self.fp, operation)
                self.locked = True

            def unlock(self):
                if self.locked:
                    fcntl.lockf(self.fp, fcntl.LOCK_UN)
                self.locked = False

        FileLock.lock = lock
        FileLock.unlock = unlock

文件的SHA256

在文件加锁以后,获取文件的data,计算sha256值。在通过命令行操作ini,将命令行中的数据,添加进data数据,获取sha256值。如果值相同,则不进行操作。

def _chksum(self, data):
    h = hashlib.sha256()
    if sys.version_info[0] >= 3:
        h.update(bytearray(data, 'utf-8'))
    else:
        h.update(data)
    return h.digest()
posted on 2019-05-02 14:55  李成石  阅读(306)  评论(0编辑  收藏  举报