美文网首页
python-10 文件

python-10 文件

作者: 巴巴11 | 来源:发表于2020-04-13 21:58 被阅读0次

    读取和写入

    要写入一个文件,你必须在打开文件时设置第二个参数来为 'w' 模式:
    >>> fout = open('output.txt', 'w')
    
    如果该文件已经存在,那么用写入模式打开它将会清空原来的数据并从新开始,所以要小心! 如果文件不存在,那么将创建一个新的文件。
    
    open会返回一个文件对象,该对象提供了操作文件的方法。write 方法将数据写入文件。
    >>> line1 = "This here's the wattle,\n"
    >>> fout.write(line1)
    24
    返回值是被写入字符的个数。文件对象将跟踪自身的位置,所以下次你调用 write 的时候,它会在文件末尾添加新的数据。
    
    >>> line2 = "the emblem of our land.\n"
    >>> fout.write(line2)
    24
    
    完成文件写入后,你应该关闭文件。
    >>> fout.close()
    如果你不关闭这个文件,程序结束时它才会关闭。
    
    格式化运算符
    write的参数必须是字符串,所以如果想要在文件中写入其它值, 我们需要先将它们转换为字符串。最简单的法是使用 str :
    
    >>> x = 52
    >>> fout.write(str(x))
    
    另一个方法是使用 格式化运算符(format operator) ,即 %。 作用于整数时,% 是取模运算符,而当第一个运算数是字符串时,% 则是格式化运算符。
    
    第一个运算数是 格式化字符串(format string) ,它包含一个或多个 格式化序列(format sequence) 。格式化序列指定了第二个运算数是如何格式化的。运算结果是一个字符串。
    
    例如,格式化序列 '%d' 意味着第二个运算数应该被格式化为一个十进制整数:
    >>> camels = 42
    >>> '%d' % camels
    '42'
    结果是字符串 '42' ,需要和整数值 42 区分开来。
    
    一个格式化序列可以出现在字符串中的任何位置,所以可以将一个值嵌入到一个语句中:
    >>> 'I have spotted %d camels.' % camels
    'I have spotted 42 camels.'
    如果字符串中有多个格式化序列,那么第二个参数必须是一个元组。 每个格式化序列按顺序和元组中的元素对应。
    
    下面的例子中使用 '%d' 来格式化一个整数, '%g' 来格式化一个浮点数,以及 '%s' 来格式化一个字符串:
    >>> 'In %d years I have spotted %g %s.' % (3, 0.1, 'camels')
    'In 3 years I have spotted 0.1 camels.'
    
    元组中元素的个数必须等于字符串中格式化序列的个数。 同时,元素的类型也必须符合对应的格式化序列:
    >>> '%d %d %d' % (1, 2)
    TypeError: not enough arguments for format string
    >>> '%d' % 'dollars'
    TypeError: %d format: a number is required, not str
    在第一个例子中,元组中没有足够的元素;在第二个例子中,元素的类型错误。
    

    文件名和路径

    文件以 **目录(directory)** (也称为“文件夹(folder)”)的形式组织起来。 每个正在运行的程序都有一个“当前目录(current directory)”作为大多数操作的默认目录。 例如,当你打开一个文件来读取时,Python 会在当前目录下寻找这个文件。
    
    `os`模块提供了操作文件和目录的函数(“os”代表“operating system”)。`os.getcwd` 返回当前目录的名称:
    >>> import os
    >>> cwd = os.getcwd()
    >>> cwd
    '/home/dinsdale'
    </pre>
    
    `cwd`代表“current working directory”,即“当前工作目录”。 在本例中,返回的结果是 `/home/dinsdale` ,即用户名为 `dinsdale` 的主目录。
    
    类似 `'/home/dinsdale'` 这样的字符串指明一个文件或者目录,叫做 **路径(path)** 。
    
    一个简单的文件名,如 `memo.txt` ,同样被看做是一个路径,只不过是 **相对路径(relative path)** ,因为它是相对于当前目录而言的。如果当前目录是 `/home/dinsdale` ,那么文件名 `memo.txt` 就代表 `/home/dinsdale/memo.txt` 。
    
    一个以 `/` 开头的路径和当前目录无关,叫做 **绝对路径(absolute path)**。要获得一个文件的绝对路径,你可以使用 `os.path.abspath` :
    >>> os.path.abspath('memo.txt')
    '/home/dinsdale/memo.txt'
    
    
    `os.path`还提供了其它函数来对文件名和路径进行操作。例如,`os.path.exists` 检查一个文件或者目录是否存在:
    >>> os.path.exists('memo.txt')
    True
    
    
    如果存在,可以通过 `os.path.isdir` 检查它是否是一个目录:
    
    >>> os.path.isdir('memo.txt')
    False
    >>> os.path.isdir('/home/dinsdale')
    True
    
    
    类似的,`os.path.isfile` 检查它是否是一个文件。
    
    `os.listdir`返回给定目录下的文件列表(以及其它目录)。
    
    >>> os.listdir(cwd)
    ['music', 'photos', 'memo.txt']
    
    接下来演示下以上函数的使用。下面的例子“遍历”一个目录,打印所有文件的名字,并且针对其中所有的目录递归的调用自身。
    
    def walk(dirname):
        for name in os.listdir(dirname):
            path = os.path.join(dirname, name)
    
            if os.path.isfile(path):
                print(path)
            else:
                walk(path)
    
    
    `os.path.join`接受一个目录和一个文件名,并把它们合并成一个完整的路径。
    
    os模块提供了一个叫做 `walk` 的函数,和我们上面写的类似,但是功能更加更富。
    
    ## 捕获异常
    试图读写文件时,很多地方可能会发生错误。如果你试图打开一个不存在的文件夹, 会得到一个输入输出错误(IOError):
    
    >>> fin = open('bad_file')
    IOError: [Errno 2] No such file or directory: 'bad_file'
    
    如果你没有权限访问一个文件:
    >>> fout = open('/etc/passwd', 'w')
    PermissionError: [Errno 13] Permission denied: '/etc/passwd'
    
    
    如果你试图打开一个目录来读取,你会得到:
    >>> fin = open('/home')
    IsADirectoryError: [Errno 21] Is a directory: '/home'
    
    为了避免这些错误,你可以使用类似 `os.path.exists` 和 `os.path.isfile` 的函数来检查,但这将会耗费大量的时间和代码去检查所有的可能性(从“Errno 21”这个错误信息来看,至少有21种可能出错的情况)。
    
    更好的办法是在问题出现的时候才去处理,而这正是 `try` 语句做的事情。 它的语法类似 `if...else` 语句:
    
    try:
        fin = open('bad_file')
    except:
        print('Something went wrong.')
    
    Python 从 `try` 子句(clause)开始执行。 如果一切正常,那么 `except` 子句将被跳过。 如果发生异常,则跳出 `try` 子句,执行 `except` 子句。
    
    使用 `try` 语句处理异常被称为是 **捕获(catching)** 异常。 在本例中,`except` 子句打印出一个并非很有帮助的错误信息。 一般来说,捕获异常后你可以选择是否解决这个问题,或者继续尝试运行,又或者至少优雅地结束程序。
    
    

    数据库
    数据库是一个用来存储数据的文件。 大多数的数据库采用类似字典的形式,即将键映射到值。 数据库和字典的最大区别是,数据库是存储在硬盘上(或者其他永久存储中), 所以即使程序结束,它们依然存在。

    dbm模块提供了一个创建和更新数据库文件的接口。
    
    打开数据库和打开其它文件的方法类似:
    >>> import dbm
    >>> db = dbm.open('captions', 'c')
    
    模式 'c' 代表如果数据库不存在则创建该数据库。 这个操作返回的是一个数据库对象,可以像字典一样使用它(对于大多数操作)。
    
    当你创建一个新项时,dbm 将更新数据库文件。
    >>> db['cleese.png'] = 'Photo of John Cleese.'
    
    当你访问某个项时,dbm 将读取文件:
    >>> db['cleese.png']
    b'Photo of John Cleese.'
    返回的结果是一个 字节对象(bytes object) ,这就是为什么结果以 b 开头。 一个字节对象在很多方面都和一个字符串很像。但是当你深入了解 Python 时, 它们之间的差别会变得很重要,但是目前我们可以忽略掉那些差别。
    
    如果你对已有的键再次进行赋值,dbm 将把旧的值替换掉:
    >>> db['cleese.png'] = 'Photo of John Cleese doing a silly walk.'
    >>> db['cleese.png']
    b'Photo of John Cleese doing a silly walk.'
    一些字典方法,例如 keys 和 items ,不适用于数据库对象,但是 for 循环依然适用:
    
    for key in db:
        print(key, db[key])
    
    与其它文件一样,当你完成操作后需要关闭文件:
    >>> db.close()
    

    序列化

    dbm 的一个限制在于键和值必须是字符串或者字节。 如果你尝试去用其它数据类型,你会得到一个错误。
    
    pickle模块可以解决这个问题。它能将几乎所有类型的对象转化为适合在数据库中存储的字符串,以及将那些字符串还原为原来的对象。
    
    pickle.dumps读取一个对象作为参数,并返回一个字符串表示(dumps 是“dump string”的缩写):
    
    >>> import pickle
    >>> t = [1, 2, 3]
    >>> pickle.dumps(t)
    b'\x80\x03]q\x00(K\x01K\x02K\x03e.'
    这个格式对人类来说不是很直观,但是对 pickle 来说很容易去解释。pickle.loads (“load string”)可以重建对象:
    
    >>> t1 = [1, 2, 3]
    >>> s = pickle.dumps(t1)
    >>> t2 = pickle.loads(s)
    >>> t2
    [1, 2, 3]
    尽管新对象和旧对象有相同的值,但它们(一般来说)不是同一个对象:
    
    >>> t1 == t2
    True
    >>> t1 is t2
    False
    换言之,序列化然后反序列化等效于复制一个对象。
    
    你可以使用 pickle 将非字符串对象存储在数据库中。 事实上,这个组合非常常用,已经被封装进了模块 shelve 中。
    

    管道

    任何可以在shell中启动的程序,也可以在 Python 中通过使用 管道对象(pipe object) 来启动。一个管道代表着一个正在运行的程序。
    
    例如,Unix 命令 ls -l 将以详细格式显示当前目录下的内容。 你可以使用 os.popen 来启动 ls :
    
    >>> cmd = 'ls -l'
    >>> fp = os.popen(cmd)
    实参是一个包含shell命令的字符串。返回值是一个行为类似已打开文件的对象。 你可以使用 readline 来每次从 ls 进程的输出中读取一行,或者使用 read 来一次读取所有内容:
    
    >>> res = fp.read()
    当你完成操作后,像关闭一个文件一样关闭管道:
    
    >>> stat = fp.close()
    >>> print(stat)
    None
    返回值是 ls 进程的最终状态。None 表示正常结束(没有出现错误)。
    
    例如,大多数 Unix 系统提供了一个叫做 md5sum 的命令,来读取一个文件的内容并计算出一个“校验和(checksum)”。
    
    你可以使用一个管道来从 Python 中运行 md5sum ,并得到计算结果:
    >>> filename = 'book.tex'
    >>> cmd = 'md5sum ' + filename
    >>> fp = os.popen(cmd)
    >>> res = fp.read()
    >>> stat = fp.close()
    >>> print(res)
    1e0033f0ed0656636de0d75144ba32e0  book.tex
    >>> print(stat)
    None
    

    编写模块
    任何包含 Python 代码的文件,都可以作为模块被导入。

    作为模块的程序通常写成以下结构:
    
    if __name__ == '__main__':
        print(linecount('wc.py'))
    __name__是一个在程序开始时设置好的内建变量。 如果程序以脚本的形式运行,__name__ 的值为 __main__ ,这时其中的代码将被执行。否则当被作为模块导入时,其中的代码将被跳过。
    
    我们做个练习,将例子输入到文件 wc.py 中,然后以脚本形式运行它。 接着,打开 Python 解释器并导入 wc 。当模块被导入后, __name__ 的值是什么?
    
    警示:如果你导入一个已经被导入了的模块,Python 将不会做任何事情。它并不会重新读取文件,即使文件的内容已经发生了改变。
    
    如果你要重载一个模块,可以使用内建函数 reload ,但它可能会出错。因此最安全的方法是重启解释器,然后重新导入模块。
    
    

    内置变量
    name

    wc.py
    def lineCount(filename):
        count = 0
        for line in open(filename):
            count += 1
        return count
    
    # print(lineCount('wc.py'))
    if __name__ == '__main__':
        print(lineCount('wc.py'))
    
    wc1.py
    import wc
    
    wc.lineCount('wc1.py')
    print("hello world\n")
    
    
    

    相关文章

      网友评论

          本文标题:python-10 文件

          本文链接:https://www.haomeiwen.com/subject/jmjomhtx.html