在脚本中打开文件时在编辑器中打开文件

Posted

技术标签:

【中文标题】在脚本中打开文件时在编辑器中打开文件【英文标题】:Opening a file in an editor while it's open in a script 【发布时间】:2016-04-11 13:45:45 【问题描述】:

我有以下代码:

import os
import sys
import tempfile
import subprocess

with tempfile.NamedTemporaryFile('w+') as f:
    if sys.platform == 'linux':
        subprocess.call('vim', f.name)
    elif sys.platform == 'nt':
        os.system(f.name)

在 Linux 上使用 vim 或在 Windows 上使用默认编辑器打开 foobar.txt。在 Linux 上它工作正常:tempfile.NamedTemporaryFile() 创建一个临时文件,vim 打开它。然而,在 Windows 上,系统会说:

该进程无法访问该文件,因为它正被另一个进程使用。

我猜这是因为脚本当前正在使用该文件。

为什么它可以在 Linux 上运行,我如何让它在 Windows 上运行?

【问题讨论】:

这是基本的 Windows I/O。所有文件都以特定的访问权限(读/写数据、删除、设置属性等)和访问共享模式打开。 NamedTemporary 根据 delete-on-close 标志的要求以删除访问权限打开文件,并共享所有访问权限(读取、写入和删除)。随后再次打开文件需要共享删除访问权限,这是大多数程序不允许的。 仅供参考,您可以通过在关闭第一个句柄之前打开文件的第二个句柄来撤消关闭时删除标志的效果。当第一个句柄关闭时,它会在文件上设置删除处置,但直到所有句柄都关闭后才会删除。使用第二个句柄通过SetFileInformationByHandle 撤消删除处置。现在您可以关闭第二个句柄,并且文件不会被删除。 哈哈,@KevinGuan 认识eryksun很久了,他解决的问题多于答案,这也是我喜欢他这个人的原因之一。 :) (希望这次他会发布答案) @KevinGuan:如果你关闭一个tempfile.NamedTemporaryFile(或一个普通的tempfile.TemporaryFile``) it will be destroyed. See [the docs](https://docs.python.org/3/library/tempfile.html) for details. Perhaps you could use a tempfile.mkstemp`文件? @KevinGuan:Unix 允许多个进程写入同一个文件,但您必须小心,正如this U&L question 中所讨论的那样。 【参考方案1】:

我以前遇到过这个问题。我的问题是我必须写入一个文件,然后将该文件的名称用作命令中的参数。

这在 Linux 中有效的原因是,正如 @PM 2Ring 在 cmets 中所说,Linux 允许多个进程写入同一个文件,但 Windows 不允许。

有两种方法可以解决这个问题。

一种是创建temporary directory 并在该目录中创建一个文件。

# Python 2 and 3
import os
import tempfile

temp_dir = tempfile.mkdtemp()
try:
    temp_file = os.path.join(temp_dir, 'file.txt')
    with open(temp_file, 'w') as f:
        pass  # Create the file, or optionally write to it.
    try:
        do_stuff(temp_file)  # In this case, open the file in an editor.
    finally:
        os.remove(file_name)
finally:
    os.rmdir(temp_dir)
# Python 3 only
import tempfile

with tempfile.TemporaryDirectory() as temp_dir:
    temp_file = os.path.join(temp_dir, 'file.txt')
    with open(temp_file, 'w') as f:
        pass  # Create the file, or optionally write to it.
    do_stuff(temp_file)
    # with tempfile.TemporaryDirectory(): automatically deletes temp_file

另一种方法是使用delete=False 创建临时文件,这样当您关闭它时,它不会被删除,稍后再手动删除。

# Python 2 and 3
import os
import tempfile

fp = tempfile.NamedTemporaryFile(suffix='.txt', delete=False)
try:
    fp.close()
    do_stuff(fp.name)
finally:
    os.remove(fp.name)

这是一个可以制作文件的小上下文管理器:

import os
import tempfile

_text_type = type(u'')

class ClosedTemporaryFile(object):
    __slots__ = ('name',)
    def __init__(self, data=b'', suffix='', prefix='tmp', dir=None):
        fp = tempfile.mkstemp(suffix, prefix, dir, isinstance(data, _text_type))
        self.name = fp.name
        if data:
            try:
                fp.write(data)
            except:
                fp.close()
                self.delete()
                raise
        fp.close()

    def exists(self):
        return os.path.isfile(self.name)

    def delete(self):
        try:
            os.remove(self.name)
        except OSError:
            pass

    def open(self, *args, **kwargs):
        return open(self.name, *args, **kwargs)

    def __enter__(self):
        return self.name

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.delete()

    def __del__(self):
        self.delete()

用法:

with ClosedTemporaryFile(suffix='.txt') as temp_file:
    do_stuff(temp_file)

【讨论】:

以上是关于在脚本中打开文件时在编辑器中打开文件的主要内容,如果未能解决你的问题,请参考以下文章

在electron.js中打开文件

打开脚本文件进行编辑的更快方法[关闭]

在git-bash中使用指定编辑器打开文本文件

如何检查文件是不是在 Linux 中打开和/或正在编辑

.sql脚本文件大于10G怎样执行,SQL2008无法打开

VSCode 怎么运行代码