Python 的 shutil.make_archive() 在 Linux 上创建点目录(当使用 tar 或 gztar 时)
Python's shutil.make_archive() creates dot directory on Linux (when using tar or gztar)
我正在使用基本的 python 脚本创建一个包含目录“directoryX”内容的存档:
shutil.make_archive('NameOfArchive', format='gztar', root_dir=getcwd()+'/directoryX/')
生成的存档文件不只是存储目录 X 的内容,而是创建一个 .存档中的文件夹(文件夹 directoryX 的内容存储在此 . 文件夹中)。
有趣的是,这只发生在 .tar 和 tar.gz 上,但不会发生在 .zip
上
使用 python 版本 -> 3.8.10
似乎在使用 .tar 或 .tar.gz 格式时,“./”的默认 base_dir 会按字面意思被接受,并创建一个名为“.”的文件夹。
我尝试使用 base_dir=os.currdir 但得到了相同的结果......
也尝试使用 python2 但得到了相同的结果。
这是 shutil.make_archive 的错误还是我做错了什么?
这是一个记录在案的行为,有点奇怪。 make_archive
的 base_dir
参数记录为:
- 是我们tar从中归档的目录(在
chdir
ing 到 root_dir
之后)
- 默认到当前目录(具体来说,
os.curdir
)
os.curdir
实际上是一个常量字符串,'.'
,并且与 tar
命令行实用程序匹配,shutil.make_archive
(和 tar.add
它实现的就) 存储“给定”的完整路径(在本例中,'./'
加上文件相对路径的其余部分)。如果你 运行 tar -c -z -C directoryX -f NameOfArchive.tar.gz .
,你最终会得到一个 tar 球,其中也充满了 ./
前缀文件(-C directoryX
与 [=17 做同样的事情=],并且 .
参数与默认值 base_dir='.'
) 相同。
我没有看到一个简单的解决方法可以保留 shutil.make_archive
的简单性;如果你尝试通过 base_dir=''
它会在它尝试 stat
''
时死掉,所以就这样了。
需要说明的是,这种行为应该没问题;一个名为 ./foo
的 tar 条目和一个名为 foo
的条目在大多数情况下是等效的。如果实在嫌麻烦,可以直接改用tarfile
模块,例如:
# Imports at top of file
import os
import tarfile
# Actual code
with tarfile.open('NameOfArchive.tar.gz', 'w:gz') as tar:
for entry in os.scandir('directoryX'):
# Operates recursively on any directories, using the arcname as the base,
# so you add the whole tree just by adding all the entries in the top
# level directory. Using arcname of entry.name means it's equivalent to
# adding os.path.basename(entry.path), omitting all directory components
tar.add(entry.path, arcname=entry.name)
# The whole loop *could* be replaced with just:
# tar.add('directoryX', arcname='')
# which would add all contents recursively, but it would also put an entry
# for '/' in, which is undesirable
目录结构如下:
directoryX/
|
\- foo
\- bar
\- subdir/
|
\- spam
\- eggs
结果 tar
的内容将是:
foo
bar
subdir/
subdir/eggs
subdir/spam
对比该:
./foo
./bar
./subdir/
./subdir/eggs
./subdir/spam
您当前的代码生成。
编码工作稍微多一些,但没有 更糟;两个导入和三行代码,并且可以更好地控制添加的内容(例如,您可以通过将 tar.add
调用包装在 if not entry.is_symlink():
块中来简单地排除符号链接,或者省略特定目录的递归添加通过有条件地将 recursive=False
设置为 tar.add
对您不想包含其内容的目录的调用;您甚至可以为 tar.add
有条件地调用提供一个 filter
函数即使涉及深度递归,也排除特定条目。
我正在使用基本的 python 脚本创建一个包含目录“directoryX”内容的存档:
shutil.make_archive('NameOfArchive', format='gztar', root_dir=getcwd()+'/directoryX/')
生成的存档文件不只是存储目录 X 的内容,而是创建一个 .存档中的文件夹(文件夹 directoryX 的内容存储在此 . 文件夹中)。
有趣的是,这只发生在 .tar 和 tar.gz 上,但不会发生在 .zip
上使用 python 版本 -> 3.8.10
似乎在使用 .tar 或 .tar.gz 格式时,“./”的默认 base_dir 会按字面意思被接受,并创建一个名为“.”的文件夹。 我尝试使用 base_dir=os.currdir 但得到了相同的结果...... 也尝试使用 python2 但得到了相同的结果。
这是 shutil.make_archive 的错误还是我做错了什么?
这是一个记录在案的行为,有点奇怪。 make_archive
的 base_dir
参数记录为:
- 是我们tar从中归档的目录(在
chdir
ing 到root_dir
之后) - 默认到当前目录(具体来说,
os.curdir
)
os.curdir
实际上是一个常量字符串,'.'
,并且与 tar
命令行实用程序匹配,shutil.make_archive
(和 tar.add
它实现的就) 存储“给定”的完整路径(在本例中,'./'
加上文件相对路径的其余部分)。如果你 运行 tar -c -z -C directoryX -f NameOfArchive.tar.gz .
,你最终会得到一个 tar 球,其中也充满了 ./
前缀文件(-C directoryX
与 [=17 做同样的事情=],并且 .
参数与默认值 base_dir='.'
) 相同。
我没有看到一个简单的解决方法可以保留 shutil.make_archive
的简单性;如果你尝试通过 base_dir=''
它会在它尝试 stat
''
时死掉,所以就这样了。
需要说明的是,这种行为应该没问题;一个名为 ./foo
的 tar 条目和一个名为 foo
的条目在大多数情况下是等效的。如果实在嫌麻烦,可以直接改用tarfile
模块,例如:
# Imports at top of file
import os
import tarfile
# Actual code
with tarfile.open('NameOfArchive.tar.gz', 'w:gz') as tar:
for entry in os.scandir('directoryX'):
# Operates recursively on any directories, using the arcname as the base,
# so you add the whole tree just by adding all the entries in the top
# level directory. Using arcname of entry.name means it's equivalent to
# adding os.path.basename(entry.path), omitting all directory components
tar.add(entry.path, arcname=entry.name)
# The whole loop *could* be replaced with just:
# tar.add('directoryX', arcname='')
# which would add all contents recursively, but it would also put an entry
# for '/' in, which is undesirable
目录结构如下:
directoryX/
|
\- foo
\- bar
\- subdir/
|
\- spam
\- eggs
结果 tar
的内容将是:
foo
bar
subdir/
subdir/eggs
subdir/spam
对比该:
./foo
./bar
./subdir/
./subdir/eggs
./subdir/spam
您当前的代码生成。
编码工作稍微多一些,但没有 更糟;两个导入和三行代码,并且可以更好地控制添加的内容(例如,您可以通过将 tar.add
调用包装在 if not entry.is_symlink():
块中来简单地排除符号链接,或者省略特定目录的递归添加通过有条件地将 recursive=False
设置为 tar.add
对您不想包含其内容的目录的调用;您甚至可以为 tar.add
有条件地调用提供一个 filter
函数即使涉及深度递归,也排除特定条目。