暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

用Python修改文件的属性

语和言 2018-09-25
1385

一、任务


在某一次应用中,需要将文本文件的编码修改为UTF-8。当我读入文本文件内容再用UTF-8编码方式写入源文件的时候,出错了。原因是文本文件是只读文件。


所以必须将文本文件去掉只读属性才能写入。这个比较简单,用os.chmod(fn, stat.S_IWRITE)即可。


有些文件具有隐藏属性,去掉隐藏属性的话,这个就不能用os.chmod了。在Windows系统中,Python需要借助于win32api才能搞定修改隐藏属性的事情。除了只读属性和隐藏属性外,我们能改变的还有系统属性和档案属性。


本文给出用win32api修改文件属性的方法。



二、环境


Win7中文旗舰版64位 + Python 3.64 64位



三、用os.chmod去掉只读属性


在硬盘上新建一个文本文件,采取系统默认的文件编码,写入“你好”二字,保存,鼠标右键添加只读属性。以下是IDLE中的操作实例。


>>> fn = r"d:\ftp\a.txt"

>>> t = open(fn).read()

>>> t

'你好'

>>> import os             # 查看文件字节数

>>> os.path.getsize(fn)

4

>>> open(fn, "wt", encoding = "utf-8").write(t)

Traceback (most recent call last):

  File "<pyshell#21>", line 1, in <module>

    open(fn, "wt", encoding = "utf-8").write(t)

PermissionError: [Errno 13] Permission denied: 'd:\\ftp\\a.txt'

>>> import stat

>>> os.chmod(fn, stat.S_IWRITE)

>>> open(fn, "wt", encoding = "utf-8").write(t)

2

>>> t2 = open(fn).read()     # 用Python读取文本文件的默认编码是"gbk"

>>> t2

'浣犲ソ'

>>> t3 = open(fn, encoding = "utf-8").read()

>>> t3

'你好'

>>> os.path.getsize(fn)

6

>>> 



四、用win32api改变文件属性的原理与方法


本人没有在Python的帮助文档中找到对win32api的详细介绍,幸亏在学习C语言和C++的时候了解过一点更改文件属性的方法。


先来介绍一下Windows系统中的文件属性。在Windows中,文件总共有15种属性,按照C/C++的宏定义常量从小到大的顺序,列成下表:



说明:

1、"只读"、“隐藏”、“系统”、“存档”为文件的四种基本属性。


2、在Windows下,鼠标点右键新建的文件具有“存档”的属性。


3、文件去掉四种基本属性后,将自动具有为“正常”属性。


4、很多病毒文件同时具有“隐藏”和“系统”属性,在Windows系统中往往很难被人发现。


5、“压缩”、“索引”和“加密”只存在于NTFS分区中,且“压缩”和“加密”不能共存。


6、文件的不同属性对应的数值都是2的整数次幂,1、2、4、16都有,唯独没有8,具体什么原因也不清楚,居然没查到相关资料。


7、默认情况下,所有文件都有索引属性,注意数值为8192的这个属性是“NOT_CONTENT_INDEXED”,所以一般的文件的属性没有8192这个整数对应的二进制位。


我们通常需要获取如下五种属性,一般能改变的是除了目录属性之外的另外四种基本属性:



注意,在Python中,因为改变Windows系统中的文件属性需要用win32api,所以这些属性对应的数值在Python中是可以使用的,但Python不认识C/C++中定义的那些常量符号,而在Python中定义常量又是一件非常麻烦的事情,我们可以定义几个自己需要的变量。


添加或者去除某种属性,需要用到二进制运算的或运算和与运算这两种运算。下面定义我们需要的几个变量(假定我们需要修改的仅仅是四个基本属性,目录属性只能获取到不能修改):


ATTR_READ_ONLY =  1

ATTR_HIDDEN    =  2

ATTR_SYSTEM    =  4

ATTR_DIR       = 16

ATTR_ARCHIVE   = 32


attrdict = {ATTR_READ_ONLY: "只读",

            ATTR_HIDDEN   : "隐藏",

            ATTR_SYSTEM   : "系统",

            ATTR_DIR      : "目录",

            ATTR_ARCHIVE  : "存档"}


获取文件的属性比较简单:


import win32api

attr = win32api.GetFileAttributes(fn)


是Python的内置模块,无需安装,可直接用import来加载使用。函数win32api.GetFileAttributes(fn)的返回值是一个正整数,如果该数的某个二进制位为1,说明文件具有该二进制位对应的权重数值相应的属性。


一般情况下,我们获取的这个整数对我们来说很陌生,我们很难把它转化为二进制再逐位比较是不是具有某个属性。这时候,我们可以自己写个函数来用字符串直接告诉我们,这个文件具有什么属性。


这里刚好用到上次推文发的将一个正整数分解成2的不同次幂的和这个函数。


# 获取文件的属性,文件不存在返回-1

def my_get_file_attr(fn):

    try:

        r = win32api.GetFileAttributes(fn)

    except:

        r = -1

    return r


# 将一个正整数分解成2的不同次幂的和,返回一个列表

def divid_n_into_different_powers_of_2_list(n):

    if n <= 0:

        return []

    else:

        return [2**pos for (pos, value)

                in enumerate(list(bin(n)[-1:1:-1]))

                if value != '0']


# 获取文件的属性的文字描述,文件不存在时返回空字符串

def my_get_file_attr_str(fn):

    attr = my_get_file_attr(fn)

    if attr < 0:

        s = ""

    else:

        attrlist = divid_n_into_different_powers_of_2_list(attr)

        sattr = [attrdict[item] for item in attrlist]

        s = " ".join(sattr)

    return s


单纯设置文件的属性也比较简单(比如设置只读属性):


win32api.GetFileAttributes(fn, 1)


这么简单的操作有一个后遗症,它在设置只读属性的同时,把所有其他的属性也都弄丢了。比如本来具有隐藏属性,添加了只读属性的同时,也去掉了隐藏属性,这是我们所不愿意看到的。我们希望,设置一个属性的时候,最好不要影响其他的属性。以只读属性为例说明一下具体操作。


添加只读属性比较容易,只需要将只读属性对应的二进制位设置为1即可,这个显然用二进制或运算比较方便:


attr = win32api.GetFileAttributes(fn)

attr = attr | ATTR_READ_ONLY

win32api.SetFileAttributes(fn, attr)


去掉只读属性需要将只读属性对应的二进制位变为0,同时不能影响文件的其他属性,这个可以用二进制与运算来实现:


attr = win32api.GetFileAttributes(fn)

attr = attr & ~ATTR_READ_ONLY

win32api.SetFileAttributes(fn, attr)



五、代码


这里给出全部代码。






六、结果


刚创建的文件的属性:存档

加上只读、系统和隐藏属性后:只读 隐藏 系统 存档

去掉只读、隐藏属性后:系统 存档





文章转载自语和言,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论