July 2014 Blog Posts

Emacs的临时文件和备份文件

MitchellChu 2014-07-18 其他技术

Emacs在编辑文件的时候实际上并非对文件本身进行编辑,而是会将要编辑的文件内容拷贝到的一个临时缓冲区(buffer)内,而我们编辑的时候,也只是对这个缓冲区的内容进行更改。为了便于在需要的时候能够方便的应对,Emacs会自动产生一些其他的辅助文件,其中最常见的有临时文件和备份文件。

(Auto-Save file)

Emacs的临时文件的文件名是使用“#”包围,这种文件一般是在Emacs中编辑时,emacs自动保存的文件,他在编辑文件的同一个目录内生成一个以#file-name#这样的文件,这个文件会在我们保存文件之后被emacs删除。这个文件的作用是为了防止在进行编辑的时候异常退出造成的损失。

1. 在Emacs内使用[C-x,C-f]打开要编辑的文件(test-file.txt)
2. 在打开的buffer中编辑内容
3. Emacs自动侦测buffer是否更改,如果更改会自动Auto-Save
4. 此时我们能够在编辑的文件同一目录下看到临时文件为:
    #test-file.txt#
5. 使用[C-x,C-s]保存当前buffer
6. 当前buffer中的内容被写入文件,#test-file.txt#消失——被Emacs自动删除

 如果你不想产生这个临时文件也是有办法的,就是关闭自动保存功能,在你启动的.emacs文件内添加下面这行

(setq auto-save-default nil) ;; 默认值是t, 要关闭直接用nil更改默认值

 当然,一般是不建议关闭的,因为在异常退出之后,如果你想要恢复自己辛苦编辑的内容,它能帮上大忙,你只要在emacs内打开你要恢复的文件,然后在恢复即可。

1. 打开要恢复的文件,如:test.txt
2. [M-x]
3. 输入:recover-file 回车
4. 确认恢复

用起来还是不错的。

 

(Backup files)

备份文件是在第一次保存的时候,如果保存的文件已经存在,Emacs会自动将当前已经存在的文件重命名作为备份文件,并将当前buffer的内容写入同名的文件中来替代原来的文件。而备份文件使用的是一个“~”作为后缀(如:file-name~)。大概的流程如下:

1. 打开文件,如:MitchellChu.txt
2. 编辑...(这涉及到临时文件的问题,忽略)
3. 在emacs内发出保存指令
4. emacs先将MitchellChu.txt保存为:MitchellChu.txt~
5. 保存完成后,Emacs将当前buffer的内容写入MitchellChu.txt
注意:此时的MitchellChu.txt已经不再是原来的那个文件,但所有连接到原来那个文件的,现在被这个新文件接管。

 当然,上面的这个流程是可以定制的,比如,我们可以要求emacs通过拷贝,而非重命名的方式来备份文件,在.emacs或者Emacs内设置个变量就成:

;; 在.emacs文件中添加下面这行表示使用拷贝模式
(setq backup-by-copying t) ;; 默认是nil,开启之后使用拷贝模式

;;;;;;;;;;;;;;;
;; 如果是在Emacs中
;; 你可以通过直接设置这个变量的值来改变模式
;;;;;;;;;;;;;;;

;; [M-x]
;; set-variable
;; backup-by-copying
;; t
;; 回车,即可修改模式

 这里同上,还是建议不要修改这个值,因为重命名的方式Mitchell个人感觉要优于拷贝模式。

备份文件默认仅会发生在Emacs第一次写入的时候,即,开启Emacs之后,第一次打开文件并保存的时候,编辑期间多次保存并不能产生多次备份动作。然而,下次重新打开Emacs,再次执行同样的动作的时候,同样在第一次保存时,Emacs是会将上次的备份文件覆盖的(如果有)。这也许是你不想要的,这时候你可以通过设置,让每次的备份文件都不同。具体的操作涉及到比较多的参数,这个功能觉得没有太大用处的,这里就不赘述,如果感兴趣,可以参看:version-control

Python用fork来创建子进程

MitchellChu 2014-07-02 其他技术 编程语言

今天看到别人的源代码中有fork子进程来操作数据。但是由于fork之后,没有及时的退出,导致系统中的进程越来越多,子进程越来越多了。自己随手写了Python下fork进程的测试代码(来说明这个问题不一定完全合适):

def fork(a):
    def now():
        import datetime
        return datetime.datetime.now().strftime("%S.%f")
    import os
    import time
    print now(), a
    if os.fork() == 0:
        print '子进程[%s]:%s' % (now(), os.getpid())
        while 1:
            a-=10
            print '子进程的a值[%s]:%s' % (now(), a)
            if a < 1:
                break
        print '准备退出子进程'
        #os._exit(0) ## 你可以在这里退出子进程
    else:
        print '父进程[%s]:%s' % (now(), os.getpid())
        while 1:
            a-=1
            print '父进程的a值[%s]:%s' % (now(), a)
            if a < 0:
                break
        time.sleep(1)
        print '等待子进程结束...'
        try:
            result = os.wait()
            if result:
                print '子进程:', result[0], result[1]
            else:
                print '没有数据!'
        except:
            print '异常哦...'
        print '父进程...'
    print '最后的值:',a
    #exit(0)  ## 你也可以在这里退出,注意,这里是父进程和子进程都共用的地方,在这里退出会导致父进程也一并退出

TIPS:

  1. os.fork() 会有两次返回值,分别是父进程和子进程的返回值
    • 在父进程中,返回的值是子进程的PID;
    • 子进程中,这个返回值为0
    • 子进程会复制父进程的上下文
    • 父子进程并不能确定执行顺序
  2. os.fork()之后,子进程一定要使用exit()或者os._exit()来退出子进程环境,建议使用os._exit()
  3. os.fork()来创建的这个代码并不是很通适,Linux是没问题的,在Windows下就是不能用的,而官方文档也有类似表述:
    Note that some platforms including FreeBSD <= 6.3, Cygwin and OS/2 EMX have known issues when using fork() from a thread
    
    Availability: Unix.

关于博主

  一枚成分复杂的网络IT分子,属于互联网行业分类中的杂牌军。