Scott's Blog

学则不固, 知则不惑

0%

Python文件操作与编码

在数据分析中,我们通常用pandasread_csv方法来读取系统中的文件,但理解这背后的原理也是非常重要的,而且幸运的是,这很简单。

Python与文件、操作系统交互

文件读取

python使用open方法接受一个路径(绝对或相对路径都可以)来读取读取文件:

1
2
path = '/Users/wittyfans/Documents/data/all_girls.csv' # :)
f = open(path)

默认打开是以 r 模式打开的,即只读。

我们可以用推导式来读取文件中的行:

1
lines = [x.rstrip() for x in open(path)]

当你使用open方法创建一个文件的时候,一定要关掉这个文件:

1
f.close()

python也考虑到了一些人可能记性不好,所以建议你使用这种方式跟文件交互:

1
2
with open(path) as f:
lines = [x.rstrip() for x in f]

with 语句会自动关闭文件。

在使用open语句的是,有一点要小心,如果当前文件夹內有一个a.txt的文件,如果你不小心使用了 f = open('./a.txt','w') 语句,那么python会立即创建一个a.txt文件,并替换掉当前的(小心⚠️)。

假设当前文件夹中有一个ftext.txt文件,如果我运行下面的代码,则可以正常显示文件中的内容:

1
2
3
with open("./ftest.txt") as f:
lines = [line for line in f]
print(lines)

如果我这样写:

1
2
3
with open("./ftest.txt",'w') as f:
lines = [line for line in f]
print(lines)

则会报错:UnsupportedOperation: not readable,因为文件依据被覆盖。 文件模式还有一个 x,它也会在path指定的路径中创建文件,不过如果路径中已经有了文件,则会创建失败。

如果你想在读取文件的时候,了解当前读取到了哪一行,或者根据行数去做控制,可以使用 f.tell() 函数。

写文件

使用文件对象的 write 或者 writelines 方法即可向文件执行写操操作:

1
2
3
4
5
with open('tmp.txt','w') as handle:
handle.writelines(x for x in open(path) if len(x) > 1)

with open('tmp.txt') as f:
lines = f.readlines()

Bytes和Unicode类型

计算机最早的编码类型是ASCII,能存一个字节的信息,对与英文刚好够用,但是如果对于汉字,最少需要两个字节才能存下来,所以后面为了统一,就制定了Unicode。因为用两个字节去存本来一个字节就可以存下来的东西,unicode会有些浪费,于是就出现了utf-8,它把一个Unicode字符根据不同的数字大小编码成1-6个字节,常用的英文字母被编码成1个字节,汉字通常是3个字节,只有很生僻的字符才会被编码成4-6个字节,这样在网络上传输的时候,可以节省很多带宽。

这些编码都是可以相互转化的,在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。

Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节,如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。

python中的字节:

1
2
x = b'ABC'# 字节类型的数据,只占用一个字节
x = 'ABC' # str,unicode类型的数据,占用多个字节

unicode类型的数据(str),可以转化成字节类型表示的数据,通过encode方法:

1
2
'ABC'.encode('ascii') # unicode类型的str,转化成ascii编码类型的数据,转化后占用1个字节
'中文'.encode('utf-8') # unicode类型的str,转化成utf-8编码类型的数据,例如从内存到硬盘

在python中,如果你想要读取10个字符:

1
2
with open(path) as f:
chars = f.read(10)

这样会从文件中读取10个字符,也就是UTF-8格式下的10个字符。

如果你以 rb 模式打开:

1
2
with open(path,'rb') as f:
data = f.read(10)

则python会读取10个字节,如果是同一份数据,则读取10个字节的这种方式会少一些数据。

对于file的seek方法要注意,如果你使用的时候出错,会导致后面的读取也出错。

参考