文件与IO

前面介绍过文件类的操作,今天给大家更加全面深入的介绍

  • 文件不存在时的写入:

你想像一个文件中写入数据,但是前提必须是这个文件在文件系统上不存在。 也就是不允许覆盖已存在的文件内容。

     ''' ========= ===============================================================
    Character Meaning
    --------- ---------------------------------------------------------------
    'r'       open for reading (default)
    'w'       open for writing, truncating the file first
    'x'       create a new file and open it for writing
    'a'       open for writing, appending to the end of the file if it exists
    'b'       binary mode
    't'       text mode (default)
    '+'       open a disk file for updating (reading and writing)
    'U'       universal newline mode (deprecated)
    ========= ==============================================================='''
    f = open('/Users/darkmoon/PycharmProjects/untitled1/FileData/te.txt','x')
    f.write("hello")
    f.close()

  • 字符串的I/O操作:

使用操作类文件对象的程序来操作文本或二进制字符串,从而模拟一个普通的文件,在单元测试中,你可以使用 StringIO 来创建一个包含测试数据的类文件对象, 这个对象可以被传给某个参数为普通文件对象的函数。

使用 io.StringIO() 和 io.BytesIO() 类来创建类文件对象操作字符串数据,相关操作跟文件的一模一样

    s = io.StringIO("hello")
    print(s.read())
    s= io.BytesIO(b"hello")
    print(s.read())
  • 读写压缩文件

gzip 和 bz2 模块可以很容易的处理这些文件。当写入压缩数据时,可以使用 compresslevel 这个可选的关键字参数来指定一个压缩级别。

import bz2,gzip
  
    with gzip.open("/Users/darkmoon/PycharmProjects/untitled1/FileData/test.gz",'w',compresslevel=3) as f:
        f.write(b"hello")
    with bz2.open("/Users/darkmoon/PycharmProjects/untitled1/FileData/test.bz2",'w',compresslevel=3) as f:
        f.write(b"hello")
    with gzip.open("/Users/darkmoon/PycharmProjects/untitled1/FileData/test.gz", 'r', compresslevel=3) as f:
        print(f.read().decode("utf-8"))
    with bz2.open("/Users/darkmoon/PycharmProjects/untitled1/FileData/test.bz2", 'r', compresslevel=3) as f:
        print(f.read().decode("utf-8"))

最后一点, gzip.open() 和 bz2.open() 还有一个很少被知道的特性, 它们可以作用在一个已存在并以二进制模式打开的文件上。比如,下面代码是可行的:

import gzip
f = open('somefile.gz', 'rb')
with gzip.open(f, 'rt') as g:
    text = g.read()
  • 固定大小记录的文件迭代

你想在一个固定长度记录或者数据块的集合上迭代,而不是在一个文件中一行一行的迭代。可以使用 iter 和 functools.partial() 函数

import mmap, os,time
from functools import partial

if __name__ == "__main__":
    filename = '/Users/darkmoon/PycharmProjects/untitled1/FileData/test.txt'
    start=time.time()
    with open(filename, 'rb') as f:

        data = iter(partial(f.read, 10), b'')

    end = time.time()
    print(end-start)
  • 读取二进制数据到可变缓冲区中

你想直接读取二进制数据到一个可变缓冲区中,而不需要做任何的中间复制操作。 或者你想原地修改数据并将它写回到一个文件中去。

if __name__ == "__main__":



    with open("/Users/darkmoon/PycharmProjects/untitled1/FileData/te.txt",'rb') as f:

        buf = bytearray(os.path.getsize("/Users/darkmoon/PycharmProjects/untitled1/FileData/te.txt"))
        f.readinto(buf)

    print(buf.decode("utf-8"))

readinto() 填充已存在的缓冲区而不是为新对象重新分配内存再返回它们。 因此,你可以使用它来避免大量的内存分配操作。

使用 f.readinto() 时需要注意的是,你必须检查它的返回值,也就是实际读取的字节数。

如果字节数小于缓冲区大小,表明数据被截断或者被破坏了(比如你期望每次读取指定数量的字节)。

另外有一个有趣特性就是 memoryview , 它可以通过零复制的方式对已存在的缓冲区执行切片操作,甚至还能修改它的内容。比如:

import  gzip,os
if __name__ == "__main__":



    with open("/Users/darkmoon/PycharmProjects/untitled1/FileData/te.txt",'rb') as f:

        buf = bytearray(os.path.getsize("/Users/darkmoon/PycharmProjects/untitled1/FileData/te.txt"))
        f.readinto(buf)
        print(buf.decode("utf-8"))

        m = memoryview(buf)

        m[2:3]=b'G'
        print(buf.decode("utf-8"))

output:
hello
heGlo
  • 内存映射的二进制文件

你想内存映射一个二进制文件到一个可变字节数组中,目的可能是为了随机访问它的内容或者是原地做些修改。

使用 mmap 模块来内存映射文件。

默认情况下, mmap.map() 函数打开的文件同时支持读和写操作。 任何的修改内容都会复制回原来的文件中。 如果需要只读的访问模式,可以给参数 access 赋值为 mmap.ACCESS_READ 。比如:

import mmap, os,time
from functools import partial

if __name__ == "__main__":
    filename = '/Users/darkmoon/PycharmProjects/untitled1/FileData/test.txt'

    start = time.time()
    fd = os.open(filename, os.O_RDWR)
    size = os.path.getsize(filename)
    with mmap.mmap(fd, size, access=mmap.ACCESS_READ) as m:
        while 1:
            line = m.readline()
            if line==b'':
                break
    end = time.time()
    print(end-start)

为了随机访问文件的内容,使用 mmap 将文件映射到内存中是一个高效和优雅的方法。 例如,你无需打开一个文件并执行大量的 seek() , read() , write() 调用, 只需要简单的映射文件并使用切片操作访问数据即可。

需要强调的一点是,内存映射一个文件并不会导致整个文件被读取到内存中。 也就是说,文件并没有被复制到内存缓存或数组中。相反,操作系统仅仅为文件内容保留了一段虚拟内存。 当你访问文件的不同区域时,这些区域的内容才根据需要被读取并映射到内存区域中。 而那些从没被访问到的部分还是留在磁盘上。所有这些过程是透明的,在幕后完成!

  • 创建临时文件和文件夹

tempfile 模块中有很多的函数可以完成这任务。 为了创建一个匿名的临时文件,可以使用 tempfile.TemporaryFile :

from tempfile import TemporaryFile

with TemporaryFile('w') as f:
    # Read/write to the file
    f.write('Hello World\n')
    f.write('Testing\n')

    f.seek(0)
    data = f.read()

TemporaryFile() 的第一个参数是文件模式,通常来讲文本模式使用 w+t ,二进制模式使用 w+b。 这个模式同时支持读和写操作,在这里是很有用的,因为当你关闭文件去改变模式的时候,文件实际上已经不存在了。 TemporaryFile() 另外还支持跟内置的 open() 函数一样的参数.

为了创建一个临时目录,可以使用 tempfile.TemporaryDirectory() 。比如:

TemporaryFile() 、NamedTemporaryFile() 和 TemporaryDirectory() 函数 应该是处理临时文件目录的最简单的方式了,因为它们会自动处理所有的创建和清理步骤。 在一个更低的级别,你可以使用 mkstemp() 和 mkdtemp() 来创建临时文件和目录。

  • 序列化Python对象

你需要将一个Python对象序列化为一个字节流,以便将它保存到一个文件、存储到数据库或者通过网络传输它。

对于序列化最普遍的做法就是使用 pickle 模块.之前做过介绍了就不介绍了。

注意:千万不要对不信任的数据使用pickle.load()。 pickle在加载时有一个副作用就是它会自动加载相应模块并构造实例对象。 但是某个坏人如果知道pickle的工作原理, 他就可以创建一个恶意的数据导致Python执行随意指定的系统命令。 因此,一定要保证pickle只在相互之间可以认证对方的解析器的内部使用。

有些类型的对象是不能被序列化的。这些通常是那些依赖外部系统状态的对象, 比如打开的文件,网络连接,线程,进程,栈帧等等。 用户自定义类可以通过提供 __getstate__() 和 __setstate__() 方法来绕过这些限制。 如果定义了这两个方法,pickle.dump() 就会调用 __getstate__() 获取序列化的对象。 类似的,__setstate__() 在反序列化时被调用。

 

import time
import threading

class Countdown:
    def __init__(self, n):
        self.n = n
        self.thr = threading.Thread(target=self.run)
        self.thr.daemon = True
        self.thr.start()

    def run(self):
        while self.n > 0:
            print('T-minus', self.n)
            self.n -= 1
            time.sleep(5)

    def __getstate__(self):
        return self.n

    def __setstate__(self, n):
        self.__init__(n)

c = Countdown(30)
f = open('/Users/darkmoon/PycharmProjects/untitled1/FileData/te.p', 'wb')
import  pickle
pickle.dump(c,f)
f.close()
f = open('/Users/darkmoon/PycharmProjects/untitled1/FileData/te.p', 'rb')

d =pickle.load(f)
print(d)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值