Python 将文件排序到新文件夹时的奇怪循环行为

Python 将文件排序到新文件夹时的奇怪循环行为,python,loops,Python,Loops,我有一个包含许多文件的文件夹,我想将这些文件移动到(待创建)子文件夹(dump_1、dump_2,…)中,以便每个子文件夹包含100个文件(或最后一个文件夹的剩余文件)。为了进行测试,我创建了如下微型文本文件: rootdir='d:/t2/' for i in range(1000): f=open(rootdir+"file_"+str(i)+".txt","w") f.write("This is file "+str(i)) f.close() 现在,创建子文件

我有一个包含许多文件的文件夹,我想将这些文件移动到(待创建)子文件夹(dump_1、dump_2,…)中,以便每个子文件夹包含100个文件(或最后一个文件夹的剩余文件)。为了进行测试,我创建了如下微型文本文件:

rootdir='d:/t2/'
for i in range(1000):
    f=open(rootdir+"file_"+str(i)+".txt","w")
    f.write("This is file "+str(i))
    f.close()
现在,创建子文件夹和移动文件的代码是

import random
files=os.listdir(rootdir)
random.shuffle(files)
count=1
while files:
    newdir=(rootdir+"dump_"+str(count).zfill(2)+"/")
    os.mkdir(newdir)
    for a,b in enumerate(files):
            os.rename(rootdir+b,newdir+b)
            files.remove(b)
            if a==99:
                break
    count+=1

结果真的很奇怪:前9个文件夹包含所需的100个文件。但下一个子文件夹包含50、25、13、6、3、2和1个文件。有人知道这是为什么吗?我如何解决?谢谢大家!

它可能与更改循环中位于其上的枚举中的变量“files”有关。例如:

>>> l = [1,2,3,4,5,6,7,8,9]
>>> for a, b in enumerate(l):
...     l.remove(b)    
...     print a
... 
0
1
2
3
4
您可以在enumerate中创建文件列表的副本(或拼接),如

for a, b in enumerate(files[:100]):

枚举
迭代列表中的元素。作为一个生成器,它在被请求时执行每个迭代。现在,在循环中,您正在从列表中删除项目,因为您仍在对其进行迭代

这样,当删除当前元素时,生成器在生成下一次迭代之前已经指向下一个元素。因此,它会跳过每一个条目:

>>> myList = [i for i in range(10)]
>>> for i, j in enumerate(myList):
        print(i, j)
        myList.remove(j)

0 0
1 2
2 4
3 6
4 8

现在您可以做的是为迭代创建一个副本,这样枚举本身就不会受到删除的影响。另一种方法是改进整个循环,这样实际上就不需要从列表中删除元素。

在必要时迭代文件并创建新目录不是更好吗:

import random
files = os.listdir(rootdir)
random.shuffle(files)
count = 1
newdir = None
for filename in files:
    if count % 100 == 1 or newdir is None:
        newdir = rootdir + "dump_" + str(count).zfill(2) + "/"
        os.mkdir(newdir)
    os.rename(rootdir + filename, newdir + filename)
    count += 1

它节省了周期并使逻辑清晰。另外,从最初的版本来看,我不知道批处理应该是99个还是100个文件。但很容易把100改成99。此外,无需从列表中删除文件。

非常感谢您的帮助!我试图在下面的代码中结合所有这些,它运行起来就像一个符咒

rootdir='d:/t2/'
import random
files = os.listdir(rootdir)
random.shuffle(files)
newdir = None
for n,filename in enumerate(files):
    if n%100 == 0 or newdir is None:
        newdir = rootdir + "dump_" + str(divmod(n,100)[0]).zfill(2) +"/"
        os.mkdir(newdir)
    os.rename(rootdir + filename, newdir + filename)

作为一种风格,同时使用
count
enumerate
循环是多余的。您可以通过删除内部循环并将要更新的代码放入
如果不计数%100:
块中来简化代码。@sr2222
count
不会像
enumerate
中的
a
那样计数文件。@poke,如果没有
for
循环,它会这样做。在这种情况下,您可以使用
count/100实现文件名中的
count
所做的相同操作。代码实际上没有那么直观,至少在目前编写的imo中是这样。。。。除非您仍然应该使用原始代码中的
枚举
技巧,以避免手动更新
计数