【问题标题】:Searching in a directory for specific file that contains a folder path and copy it in python在目录中搜索包含文件夹路径的特定文件并将其复制到 python
【发布时间】:2013-03-08 21:31:30
【问题描述】:

我对 python 很陌生,每天都能学到很多东西。 我想做一个自动脚本来帮助我的工作。

我有一个包含一些文件的特定文件夹,我不希望我的工具是特定于文件的,因为我想重用这个脚本,所以我希望它在文件中查找特定标题,

可以说文件在“paths”行的中间某处,在它下面有许多路径,例如“file path="Some path"

我希望我的脚本转到我指定的目录并查找包含此标题“路径”的文件 复制其中一条路径(它们就在它下面),就是这样。

然后我将使用此路径来下载文件等等,但这部分我已经完成了。 我只是不知道如何在给定特定文件夹时在文件中查找特定字符串并复制我想要的字符串。

假设我有一个文件夹 (C:\Folder) 在文件夹中我有 3 个文件 (1,2,3)

我想查找包含这种模式“路径”的文件 并复制在其下指定的路径或至少其中一个。 它们就像“文件路径=C:\somepath” 所以文件内容是这样的

废话

废话

路径

文件路径=C:\somepath

文件路径=C:\somepath2

废话

我想复制 C:\somepath 并将其用作我工作的一部分。

非常感谢所有帮助者,这对我来说非常重要。

【问题讨论】:

  • 好吧,如果您需要帮助,您应该先用正确的英语解释您的问题。现在,用你搞砸的标点符号和语法,不可能听懂你想说的话。

标签: python string path copy


【解决方案1】:

第一步是查看目录中的所有文件。那是os.listdir

接下来,您需要循环打开每个文件。所以,到目前为止,我们得到了:

for filename in os.listdir(directory):
    with open(filename) as f:

现在,我们如何处理每个文件?有几个不同的选项——我们可以读入整个文件(或mmap它)然后使用str.find或正则表达式方法来解析它,或者我们可以逐行跟踪我们的状态,或者我们可以使用itertools 函数转换行序列,或者我们可以构建一个状态机并运行它,或者……

我认为对于新手来说最简单的方法是手动逐行进行。但是让我们将它包装在一个函数中。所以:

def parse_file(f):
    paths = []
    found_paths = False
    for line in f:
        line = line.strip()
        if not found_paths:
            if line == 'paths':
                found_paths = True
        else:
            if line.startswith('file path='):
                paths.append(line[len('file path='):])
            else:
                break
    return paths

paths = []
for filename in os.listdir(directory):
    with open(filename) as f:            
        paths.append(parse_file(f))

找到第一行后如何停止?

阅读第一行后只需break。所以,而不是这个:

if line.startswith('file path='):
    paths.append(line[len('file path='):])
else:
    break

这样做:

if line.startswith('file path='):
    paths.append(line[len('file path='):])
break

我如何修复它以将路径放在字典中的不同索引中,因为它将所有路径都放在第一个字段中

嗯,现在,您不是创建字典,而是创建列表。

如果您想要一个字典,例如,将每个文件映射到该文件中的文件路径列表,这很容易。而不是这个:

paths = []
for filename in os.listdir(directory):
    with open(filename) as f:
        paths.append(parse_file(f))

这样做:

paths = {}
for filename in os.listdir(directory):
    with open(filename) as f:            
        paths[filename] = parse_file(f)

但是,如果您只需要一个值,那么一开始就不构建列表可能会更简单。如果找到了,则只需要返回路径名,如果没有,则返回不可能是路径名的内容(如 None)。

如何修改有问题的路径。因为文件中的路径以这种格式保存 - 我只想复制 C:\folder\folder

嗯,首先,我的代码甚至找不到具有该格式的任何内容。你要求找到像file path=… 这样的行,所以我使用了startswith,但<file path= 并没有以它开头。因此,您首先需要更改您检查的startswith。同时,您还需要处理引号和尖括号。

在这一点上,看起来只是愚蠢的文本处理可能不是正确的答案。这看起来像 XML。解析 XML 文档的最简单方法是使用 XML 解析器,例如 xml.elementtree。如果它不是 XML 文档,只是一个基于行的文档,其中有 XML 节点,您可以仍然尝试将每一行解析为 XML 文档,但使用 @987654339 可能更容易@ 带有合适的正则表达式(例如,r'<file path="(.*?)"/>' 将只匹配引号之间的部分)。在不知道您的实际输入文本是什么样子的情况下,我无法为您提供比这更具体的内容。

最后,在您完成该步骤后,您似乎想要从目录路径中删除尾随反斜杠,因此即使文件有 C:\folder\folder\,您也会得到 C:\folder\folder。您可以为此使用os.path 中的函数,但如果您确定路径将始终采用Windows 格式,则使用rstrip('\\') 告诉它删除任何尾随反斜杠可能会更简单。 (注意那里的双反斜杠,因为您需要在 Python 字符串中转义反斜杠。)

【讨论】:

  • 非常感谢,但我的问题很少。找到第一行后如何停止?或者我如何修复它以将路径放在字典中的不同索引中,因为它将所有路径都放在第一个字段中(最后我想使用一个)我的第二个问题是如何修改有问题的路径。因为文件中的路径以这种格式保存 - 并且我只想复制 C:\folder\folder。谢谢!!!
  • 既然你有很多问题,让我更新答案。
  • 好的,不需要回答第一个问题我只是做路径[0][0],但是我如何操作路径,现在脚本的结果是“C:\folder\folder \"/> 在文件中它是 - 我想要的结果是 C:\folder\folder - 谢谢!
  • 嗯,我已经回答了这两个部分(以及它们的所有子部分)。正如我所说,如果您尝试解析 XML,那么一开始就应该这样说,而且您可能不应该这样做。
  • 是的,它是一个 xml 文件,对不起,我没有说。我在玩你说的 xml 解析器,有一些问题。所以我的文件有很多文本,但在中间我有 并且在下面我有 和更多这种格式的路径。现在脚本将该行复制到列表中作为 "C:\folder\folder\"/> 并且我希望将结果作为 Windows 中的正常路径。您建议对字符串进行操作还是使用 xml 解析器?xml 解析器有点难,因为路径是一个深子-tree child。我已经非常接近没有 xml 解析器的解决方案
【解决方案2】:

从您的 cmets 中,您的数据实际上是 XML,而您想要的是第一个 paths 节点中每个(或第一个)file 节点的 path 属性。

就 XML 解析器而言,这实际上更容易编写,而且更健壮。

例如,这些可能都是有效的file 节点:

<file path="C:\Foo\Bar" />
<file path="C:\Baz\Qux"/>
    <file path="C:\Foo\Bar" />
<file path="C:\Spam\Eggs\" alt="other attribute cruft" />
<file alt="other attribute cruft" path="C:\Spam\Eggs\" />
<file path="C:\Spam\Spam\"></file>

您甚至可能会看到这些,无论是否合法:

<file path='C:\Eggs\"Spam Spam Spam"\"Spammity Spam"'/>

您不想尝试以纯文本形式处理所有这些可能性。但是,如果您不处理所有这些文件(以及更多),墨菲定律保证您最终会遇到一个文件,其中包含您不处理的文件。

有很多不同的 XML 解析器,甚至内置在标准库中,但我认为最简单的是 ElementTree。所以:

import os
import os.path
import xml.etree.ElementTree as ET

filepaths = {}
for filename in os.listdir(directory):
    try:
        doc = ET.parse(os.path.join(directory, filename))
        paths = doc.find('paths')
        filepaths[filename] = [f.attrib['path'] for f in paths.findall('file')]
    except Exception as e:
        # You may want to log something, treat different exceptions differently, etc.
        pass

应该很容易弄清楚如何更改它以处理所有paths 节点而不是第一个节点,或者paths 下的第一个file 节点而不是所有节点,或者第一个file具有path 属性等的节点。

如果您使用的是 Python 2.x,并且文件非常大,这可能会有点慢。但是您可以通过显式使用cElementTree 来解决这个问题。这样做很常见:

try:
    import xml.etree.cElementTree as ET
except ImportError:
    import xml.etree.ElementTree as ET

如果可能的话,这将为您提供快速的“C”实现,否则,在 CPython 2.5+(包括 3.x,两者合并在一起)、PyPy 等中,这将为您提供慢速实现。


同时,您向其他 cmets 询问了您原始帖子中没有的其他内容:

我只需要……把反斜杠变成 /

这很容易。只需在每条路径s 上调用s.replace('\\', '/')

但是,这样做有点奇怪。反过来是很常见的(它甚至内置在标准库中——os.path.normpath 将在 POSIX 上单独保留斜杠,但在 Windows 上将它们转换为反斜杠),但是从原生 Windows 到 POSIX 通常是更大的一部分操作,例如构建 URL……在这种情况下,您可能希望使用更高级别的函数。

在文件中 - 我想要的结果是 C:\folder\folder

在这里,听起来您想去掉任何尾随反斜杠。再说一次,这是一件很奇怪的事情,你可能真的想做一些比这更高级的事情(比如os.path.dirname 可能吗?),但很简单:s.rstrip('\\')

当然,最后两个相互矛盾——如果你想要的结果是C:\folder\folder,并且你将反斜杠转换为正斜杠,你将不会得到你想要的结果。

但希望我已经给了你足够的东西来构建你真正想要的任何东西。

【讨论】:

  • 我不知道我做错了什么,我的文件看起来像这样 - 并在它下面 以及更多路径相同的格式,在文件顶部以 结尾之后,在底部还有更多内容。我运行你写的代码,我在文件路径中得到的是空的 {} 而在路径中我没有得到。
猜你喜欢
  • 2016-10-23
  • 1970-01-01
  • 1970-01-01
  • 2022-10-17
  • 1970-01-01
  • 2010-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多