Python os.rename()和os.renames()用法的区别——总结2

1. 前言

今天看了os和os.path模块的官方文档,其中os.rename()和os.renames()刚开始没有整明白到底啥区别,接着自己点进去看源码,再结合了几篇技术博客和实践,算是对于os.rename和os.renames的使用有了基本了解,特地纪录下,方便日后查看。如果有理解不当的地方,还请大家指出交流。

2. os.rename 和os.renames()

2.1 官方的文档

  • os.rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)
    Rename the file or directory src to dst. If dst exists, the operation will fail with an OSError subclass in a number of cases.

  • os.renames(old, new)
    Recursive directory or file renaming function. Works like rename(), except creation of any intermediate directories needed to make the new pathname good is attempted first. After the rename, directories corresponding to rightmost path segments of the old name will be pruned away using removedirs().
    注解 This function can fail with the new directory structure made if you lack permissions needed to remove the leaf directory or file.
    看完英文文档,一开始还是不明白os.renames()到底怎么递归,怎么用的。
    接下来看看源码,发现os.renames调用rename(),只不过在调用之前,用的是makedirs()递归创建目录。所以本质上os.renames()应该是通过makedirs()来实现递归的。

def renames(old, new):
    head, tail = path.split(new)
    if head and tail and not path.exists(head):
        makedirs(head)
    rename(old, new)
    head, tail = path.split(old)
    if head and tail:
        try:
            removedirs(head)
        except OSError:
            pass

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2.2 用法比较

再说用法前,为了方便表述准确,我们学习一下os.path.split()方法
看源码:

def split(p):
    """Split a pathname.
Return tuple (head, tail) where tail is everything after the final slash.
Either part may be empty."""</span>
p <span class="token operator">=</span> os<span class="token punctuation">.</span>fspath<span class="token punctuation">(</span>p<span class="token punctuation">)</span>
seps <span class="token operator">=</span> _get_bothseps<span class="token punctuation">(</span>p<span class="token punctuation">)</span>
d<span class="token punctuation">,</span> p <span class="token operator">=</span> splitdrive<span class="token punctuation">(</span>p<span class="token punctuation">)</span>
<span class="token comment"># set i to index beyond p's last slash</span>
i <span class="token operator">=</span> <span class="token builtin">len</span><span class="token punctuation">(</span>p<span class="token punctuation">)</span>
<span class="token keyword">while</span> i <span class="token operator">and</span> p<span class="token punctuation">[</span>i<span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token operator">not</span> <span class="token keyword">in</span> seps<span class="token punctuation">:</span>
    i <span class="token operator">-=</span> <span class="token number">1</span>
head<span class="token punctuation">,</span> tail <span class="token operator">=</span> p<span class="token punctuation">[</span><span class="token punctuation">:</span>i<span class="token punctuation">]</span><span class="token punctuation">,</span> p<span class="token punctuation">[</span>i<span class="token punctuation">:</span><span class="token punctuation">]</span> <span class="token comment"># now tail has no slashes</span>
<span class="token comment"># remove trailing slashes from head, unless it's all slashes</span>
head <span class="token operator">=</span> head<span class="token punctuation">.</span>rstrip<span class="token punctuation">(</span>seps<span class="token punctuation">)</span> <span class="token operator">or</span> head
<span class="token keyword">return</span> d <span class="token operator">+</span> head<span class="token punctuation">,</span> tail
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

官方说明:

  • os.path.split(path)
    Split the pathname path into a pair, (head, tail) where tail is the last pathname component and head is everything leading up to that. The tail part will never contain a slash; if path ends in a slash, tail will be empty. If there is no slash in path, head will be empty. If path is empty, both head and tail are empty. Trailing slashes are stripped from head unless it is the root (one or more slashes only). In all cases, join(head, tail) returns a path to the same location as path (but the strings may differ). Also see the functions dirname() and basename().

翻译过来就是说,os.path.split()的功能是把给定的一个路径pathname,以最后一个斜线作为分分隔符,得到一个(head, tail),即(头, 尾)的元组。

  • 如果pathname中没有斜线,则head为空;
  • 如果pathname最后以斜线结尾,则tail为空;
  • 如果pathname为空,则head和tail都是空。
    比如:
>>> import os
>>> os.path.split('C:/a/b/c.text')
('C:/a/b', 'c.text')
>>> os.path.split('C:/a/b')
('C:/a', 'b')
>>> os.path.split('C:/a/')
('C:/a', '')
>>> os.path.split('c.text')
('', 'c.text')
>>> os.path.split('')
('', '')

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

理解了os.path.split()的用法,明确了head和tail的概念,接下来我们就进入os.rename()和os.path.renames()用法上的比较:

2.2.1 os.rename(oldpath,newpath)

oldpath(oldhead, oldtail)
newpath(newhead, newtail)
对于os.rename(oldpath, newpath)而言,它的功能本质是有点像把文件oldtail(文件夹或者文件均可)移到newhead文件夹下并重命名为newtail(文件或者文件夹)。它只可以更改oldtail部分,不能更改oldhead部分,即不可以更改上级目录部分。

  1. 如果oldhead或者newhead不存在,均会报错:FileNotFoundError: [WinError 3] 系统找不到指定的路径。
  2. 如果oldhead存在,oldtail不存在时,报错:FileNotFoundError: [WinError 2] 系统找不到指定的文件。
  3. 如果newhead存在,newtail存在,会报错:FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件。

示例:C:\Users\Jock\Desktop\test\1.jpg

# 重命名test文件夹 为test_a
>>> os.rename(r'C:\Users\Jock\Desktop\test', r'C:\Users\Jock\Desktop\test_a')  
# 重命名1.jpg文件为2.jpg
>>> os.rename(r'C:\Users\Jock\Desktop\test_a\1.jpg', r'C:\Users\Jock\Desktop\test_a\2.jpg')  
# newhead不存在,报错:FileNotFoundError: [WinError 3] 系统找不到指定的路径。
>>> os.rename(r'C:\Users\Jock\Desktop\test_a\2.jpg', r'C:\Users\Jock\Desktop\test_b\2.jpg')
FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'C:\\Users\\Jock\\Desktop\\test_a\\2.jpg' -> 'C:\\Users\\Jock\\Desktop\\test_b\\2.jpg' 
# oldhead不存在,报错:FileNotFoundError: [WinError 3] 系统找不到指定的路径。
>>> os.rename(r'C:\Users\Jock\Desktop\test\2.jpg', r'C:\Users\Jock\Desktop\test_a\1.jpg')
FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'C:\\Users\\Jock\\Desktop\\test\\2.jpg' -> 'C:\\Users\\Jock\\Desktop\\test_a\\1.jpg'
# oldhead存在,oldtail不存在时,报错:FileNotFoundError: [WinError 2] 系统找不到指定的文件
>>> os.rename(r'C:\Users\Jock\Desktop\test_a\2.jpg', r'C:\Users\Jock\Desktop\test_a\1.jpg')
FileNotFoundError: [WinError 2] 系统找不到指定的文件。: 'C:\\Users\\Jock\\Desktop\\test_a\\2.jpg' -> 'C:\\Users\\Jock\\Desktop\\test_a\\1.jpg'
# 重新复制一张1.jpg文件到C:\Users\Jock\Desktop\test_a路径下,现在test_a包含1.jpg和2.jpg
# newhead存在,newtail存在,会报错:FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件
>>> os.rename(r'C:\Users\Jock\Desktop\test_a\1.jpg', r'C:\Users\Jock\Desktop\test_a\2.jpg')
FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件。: 'C:\\Users\\Jock\\Desktop\\test_a\\1.jpg' -> 'C:\\Users\\Jock\\Desktop\\test_a\\2.jpg'

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
2.2.2 os.renames(oldpath, newpath)

oldpath(oldhead, oldtail)
newpath(newhead, newtail)
对于os.renames(oldpath, newpath)而言,它可以只更改oldtail部分,也可以只更改oldhead部分,还可以同时更改oldhead和oldtail,对于newpath的newhead没有限制,只要有权限访问,如果newhead不存在,直接创建。

  1. 如果oldhead不存在,会报错:FileNotFoundError: [WinError 3] 系统找不到指定的路径。
  2. 如果oldhead存在,oldtail不存在时,报错:FileNotFoundError: [WinError 2] 系统找不到指定的文件。
  3. 如果newhead存在,newtail存在,会报错:FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件。

示例:C:\Users\Jock\Desktop\test\1.jpg

# 重命名test文件夹 为test_a
>>> os.renames(r'C:\Users\Jock\Desktop\test', r'C:\Users\Jock\Desktop\test_a')
# 重命名1.jpg文件为2.jpg
>>> os.renames(r'C:\Users\Jock\Desktop\test_a\1.jpg', r'C:\Users\Jock\Desktop\test_a\2.jpg')
# newhead不存在,直接创建newhead然后重命名,这里相当于修改了目录,文件名没有变
>>> os.renames(r'C:\Users\Jock\Desktop\test_a\2.jpg', r'C:\Users\Jock\Desktop\test_b\2.jpg')
# 同时修改目录和文件名
>>> os.renames(r'C:\Users\Jock\Desktop\test_b\2.jpg', r'C:\Users\Jock\Desktop\test_a\1.jpg')
# 如果oldhead不存在,会报错:FileNotFoundError: [WinError 3] 系统找不到指定的路径。
>>> os.renames(r'C:\Users\Jock\Desktop\test_b\1.jpg', r'C:\Users\Jock\Desktop\test_a\1.jpg')
FileNotFoundError: [WinError 3] 系统找不到指定的路径。: 'C:\\Users\\Jock\\Desktop\\test_b\\1.jpg' -> 'C:\\Users\\Jock\\Desktop\\test_a\\1.jpg'
# oldhead存在,oldtail不存在时,报错:FileNotFoundError: [WinError 2] 系统找不到指定的文件
>>> os.renames(r'C:\Users\Jock\Desktop\test_a\2.jpg', r'C:\Users\Jock\Desktop\test_a\1.jpg')
FileNotFoundError: [WinError 2] 系统找不到指定的文件。: 'C:\\Users\\Jock\\Desktop\\test_a\\2.jpg' -> 'C:\\Users\\Jock\\Desktop\\test_a\\1.jpg'
# 重新复制一张1.jpg文件到C:\Users\Jock\Desktop\test_a路径下,现在test_a包含1.jpg和2.jpg
# 如果newhead存在,newtail存在,会报错:FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件
>>> os.renames(r'C:\Users\Jock\Desktop\test_a\1.jpg', r'C:\Users\Jock\Desktop\test_a\2.jpg')
Traceback (most recent call last):
FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件。: 'C:\\Users\\Jock\\Desktop\\test_a\\1.jpg' -> 'C:\\Users\\Jock\\Desktop\\test_a\\2.jpg'

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3. 小结

  1. os.path.split(path), 是把path以最后一个斜线为分隔符,切割为head和tail,以(head, tail)元组的形势返回。
  2. os.rename(oldpath, newpath),它是只能重命名最后的tail部分,不能对head部分进行修改。tail的上级目录无法被修改,且无法创建新的目录。
  3. os.renames(oldpath, newpath),它既可以重命名tail部分,也可以修改head部分,还可以创建新的目录。
  4. 如果newpath已经存在,那么os.rename()和os.renames()都会报错:FileExistsError: [WinError 183] 当文件已存在时,无法创建该文件。

4. 参考文献

  1. os — 操作系统接口模块
  2. os.path — 常见路径操作
  3. 学习python之 os.rename VS os.renames

后记:
我从本硕药学零基础转行计算机,自学路上,走过很多弯路,也庆幸自己喜欢记笔记,把知识点进行总结,帮助自己成功实现转行。
2020下半年进入职场,深感自己的不足,所以2021年给自己定了个计划,每日学一技,日积月累,厚积薄发。
如果你想和我一起交流学习,欢迎大家关注我的微信公众号每日学一技,扫描下方二维码或者搜索每日学一技关注。
这个公众号主要是分享和记录自己每日的技术学习,不定期整理子类分享,主要涉及 C – > Python – > Java,计算机基础知识,机器学习,职场技能等,简单说就是一句话,成长的见证!
每日学一技

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值