【问题标题】:Iterate excel files and output in one folder in Python迭代excel文件并在Python中的一个文件夹中输出
【发布时间】:2019-01-24 12:30:57
【问题描述】:

我有一个文件夹和子文件夹结构如下:

D:/src
├─ xyz.xlsx
├─ dist
│  ├─ xyz.xlsx
│  ├─ xxx.zip
│  └─ xxy.xlsx
├─ lib
│  ├─ xy.rar
│  └─ xyx.xlsx
├─ test
│  ├─ xyy.xlsx
│  ├─ x.xls
│  └─ xyz.xlsx

我想从源目录和子目录中提取所有 excel 文件(xls 或 xlsx),根据 excel 文件名删除重复文件并将所有唯一文件放在 D:/dst 目录中。如何在 Python 中获得以下结果?谢谢。 预期结果:

D:/dst
├─ xyz.xlsx
├─ xxy.xlsx
├─ xyx.xlsx
├─ xyy.xlsx
├─ x.xls

这是我尝试过的:

import os

for root, dirs, files in os.walk(src, topdown=False):
    for file in files:
        if file.endswith('.xlsx') or file.endswith('.xls'):
            #print(os.path.join(root, file))
            try:
                df0 = pd.read_excel(os.path.join(root, file))
                #print(df0)
            except:
                continue
            df1 = pd.DataFrame(columns = [columns_selected])
            df1 = df1.append(df0, ignore_index = True)
            print(df1)
            df1.to_excel('test.xlsx', index = False)

【问题讨论】:

  • 我认为您可以通过shutil.copytree() 完成所有这些工作。见问题Copying specific files to a new folder, while maintaining the original subdirectory tree
  • @ahbon,解决这个问题还有什么不幸的吗?
  • 感谢您的提问。我明天试试,如果有问题我会告诉你的。
  • @martineau 您提到的解决方案将所有 xlsx 和 xls 文件复制到新文件夹 D:/dst,但它保留原始子目录。如果我只想将它们放在一个文件夹中而忽略其原始子目录怎么办?
  • 虽然您添加的所有 pandas 数据框内容都让人分心,并且与您的问题并不完全相关,但它暴露了——我认为——所谓的 XY Problem,因为它揭示了 为什么 你想要做这个文件复制。如果我理解正确,那么确实没有必要先将所有文件复制到一个文件夹中——只需使用找到它们的过程来复制它们,而不是驱动你想要做的它们的连接。这将大大减少需要完成的 I/O。

标签: python operating-system


【解决方案1】:

我认为这会做你想要的:

import os
import shutil


src = os.path.abspath(r'.\_src')
dst = os.path.abspath(r'.\_dst')
wanted = {'.xls', '.xlsx'}

copied = set()

for root, dirs, filenames in os.walk(src, topdown=False):
    for filename in filenames:
        ext = os.path.splitext(filename)[1]
        if ext in wanted and filename not in copied:
            src_filepath = os.path.join(root, filename)
            shutil.copy(src_filepath, dst)
            copied.add(filename)

【讨论】:

  • 您的解决方案完美解决了我将excel文件复制到一个文件夹的问题。非常感谢。
  • ahbon:很高兴听到这个消息,不客气。很抱歉我的shutil.copytree() 的建议可能造成了干扰。虽然它可以用它来完成,但在这种情况下,它并不是一个很好的方法。
  • 正要分享this answer you provided另一个问题。
  • @aneroid:我最初也认为这个答案会是一个好方法,但是当我最终——经过多次讨论——能够理解目标是什么时,我决定它不会。尽管从技术上讲,可以通过“滥用”ignore 选项来指出它忽略了所有内容,但我认为这有点过分了。这个问题所需要的只是遍历文件夹系统层次结构的能力,因此os.walk() 将是更合乎逻辑(更好)的选择。
【解决方案2】:

既然你已经有了glob.glob,你就不需要再做os.walk,反之亦然。但是由于 glob 一次只匹配一个模式,并且无法在扩展中表示可选的额外“x”,因此您要么需要两次 glob 循环 - 每个扩展一次;或者使用可以匹配'*.xlsm'等的glob.glob( 'D:\\src\\*.xls*')

对于每个匹配的文件,使用shutil.move:

for file in glob.glob('D:\\src\\*.xls*'):
    shutil.move(file, 'D:\\dst\\' + os.path.basename(file))

使用os.walk,您可以在同一循环中使用fnmatch.fnmatch 进行每个扩展检查:

for root, dirs, files in os.walk('D:\\src'):
    for file in files:
        if fnmatch.fnmatch(file, '*.xls') or fnmatch.fnmatch(file, '*.xlsx'):
            shutil.move(f'{root}\\{file}', f'D:\\dst\\{file}')
            # shutil.move(root + '\\' + file, 'D:\\dst\\' + file)

【讨论】:

  • 为什么还要打电话给os.walk(),然后在第一次迭代后退出?我认为这个问题尚不清楚,并已要求 OP 进行澄清。
  • 谢谢@aneroid。我觉得shutil.copy在不改变原始数据的情况下会更好,你觉得呢?
  • 感谢您的帮助。您的解决方案仅将 D:/src - xyz.xlsx 复制到 D:/dst,而不是其子文件夹中的 excel 文件。
  • @martineau 我从 OP 的代码中收集到他/她想在第一个文件夹/迭代后停止。即使使用 glob,每个扩展都需要两个循环,并且没有 recursive=True。所以认为os.walk() 可以简化这一点。无论如何,从 OP 的帖子来看,他们确实想做子目录。
  • @ahbon 是的,如果您希望原始数据保留在'D:\src' 中,可以使用copy 而不是move。我已经删除了break,这样循环在第一次迭代后就不会停止。从您的代码来看,您似乎只想使用顶层。此外,如果您正在递归复制,则需要修改 f'D:\\dst\\{file}' 以拥有每个文件的父文件夹。否则它将复制平面,没有子目录。看看shutil.copytree()
猜你喜欢
  • 2021-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多