zoukankan      html  css  js  c++  java
  • 读写文本数据

    使用其他分隔符或行终止符打印

    问题:

      你想使用print() 函数输出数据,但是想改变默认的分隔符或者行尾符。

    解决方案:

      可以使用在print() 函数中使用sep 和end 关键字参数,以你想要的方式输出。比如:

     1 #正常输出
     2 print('dmeon', 89 , 8, 23)
     3 
     4 #指定分隔符,
     5 print('dmeon', 89 , 8, 23, sep=',')
     6 
     7 #指定结尾符号
     8 print('dmeon', 89 , 8, 23, sep=',',end='!!!
    ')
     9 
    10 #使用end 参数也可以在输出中禁止换行。比如:
    11 for i in range(5):
    12     print(i, end=' ')
    13 
    14 #另外一种添加分隔符的方法
    15 print()
    16 print('分隔符的方法'.center(30, '-'))
    17 s1 = ('dmeon', 89 , 8, 23)
    18 result = ' '.join((str(s) for s in s1))
    19 print(result)
    20 
    21 #高逼格的方法
    22 print("s1的值", s1)
    23 print('高逼格的输出方式', *s1,sep=',')

    以上代执行输出的结果为:

    dmeon 89 8 23
    dmeon,89,8,23
    dmeon,89,8,23!!!
    0 1 2 3 4 
    ------------分隔符的方法------------
    dmeon 89 8 23
    s1的值 ('dmeon', 89, 8, 23)
    高逼格的输出方式,dmeon,89,8,23

    读写字节数据

    问题:

      你想读写二进制文件,比如图片,声音文件等等

    解决方案:

      使用模式为rb 或wb 的open() 函数来读取或写入二进制数据。比如:

     1 #使用with打开文件,不需要考虑文件close的问题,rb模式是使用读二进制的模式打开
     2 with open('/tmp/go.pdf', 'rb') as f:
     3     #获取文件中的内容
     4     data = f.read()
     5 
     6 #wb是写的二进制模式打开,当文件存在会覆盖文件已有的内容,文件不存在会创建
     7 with open('/tmp/test.bin','wb') as f:
     8     f.write(b'Hello World')
     9 
    10 #天坑,读取二进制数据的时候,字节字符串和文本字符串的语义差异可能会导致一个潜在的陷阱
    11 t = 'Hello World'
    12 print("t中0索引第一个元素为:", t[0])
    13 
    14 #循环t并打印每个元素
    15 for i in t:
    16     print('循环t中的每个元素:', i)
    17 
    18 #坑的地方来了
    19 print('*'*30)
    20 b = b'Hello World'
    21 print('b中0索引的元素:', b[0])
    22 
    23 #循环bytes类型b变量中的每个元素
    24 for x in b:
    25     print('循环b中的每个元素:', x)

    以上代执行输出的结果为:

    t中0索引第一个元素为: H
    循环t中的每个元素: H
    循环t中的每个元素: e
    循环t中的每个元素: l
    循环t中的每个元素: l
    循环t中的每个元素: o
    循环t中的每个元素:  
    循环t中的每个元素: W
    循环t中的每个元素: o
    循环t中的每个元素: r
    循环t中的每个元素: l
    循环t中的每个元素: d
    ******************************
    b中0索引的元素: 72
    循环b中的每个元素: 72
    循环b中的每个元素: 101
    循环b中的每个元素: 108
    循环b中的每个元素: 108
    循环b中的每个元素: 111
    循环b中的每个元素: 32
    循环b中的每个元素: 87
    循环b中的每个元素: 111
    循环b中的每个元素: 114
    循环b中的每个元素: 108
    循环b中的每个元素: 100

    如果你想从二进制模式的文件中读取或写入文本数据,必须确保要进行解码和编码操作。比如:

    1 with open('/tmp/test.bin', 'rb') as f:
    2     data = f.read(16)
    3     print('data的数据类型:', type(data))
    4     print('data的数据:', data)
    5 
    6     text = data.decode('utf-8')
    7     print('data转码以后的数据类型:', type(text))
    8     print('text的数据:', text)

    以上代执行输出的结果为:

    data的数据类型: <class 'bytes'>
    data的数据: b'Hello World'
    data转码以后的数据类型: <class 'str'>
    text的数据: Hello World

    文件不存在才能写入

    问题:

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

    解决方案:

      可以在open() 函数中使用x 模式来代替w 模式的方法来解决这个问题。比如:

     1 #如果文件存在,会覆盖内容,如果文件不存在会创建文件并写入内容
     2 with open('/tmp/test.bin', 'wt') as f:
     3     f.write('Hello
    ')
     4 
     5 #如果文件存在,会报异常,否则创建文件并写入内容,如果文件是二进制,使用wb代替
     6 try:
     7     f = open('/tmp/test.bin', 'xt')
     8 except Exception as e:
     9     print(e)
    10 else:
    11     f.write('Hello
    ')
    12 finally:
    13     f.close()

    以上代执行输出的结果为:

    [Errno 17] File exists: '/tmp/test.bin'

    字符串的I/O 操作

    问题:

      你想使用操作类文件对象的程序来操作文本或二进制字符串

    解决方案:

      使用io.StringIO() 和io.BytesIO() 类来创建类文件对象操作字符串数据。比如:

     1 import io
     2 
     3 s = io.StringIO()
     4 print(s.write('Hello World
    '))
     5 
     6 print('This is a test', file=s)
     7 
     8 #获取s中的内容
     9 content = s.getvalue()
    10 print('s中的内容为:', content)
    11 
    12 #读取5个长度的内容
    13 s = io.StringIO('Hello
    World
    ')
    14 print("五个字符的内容:")
    15 print(s.read(5))
    16 
    17 #读取剩余的内容
    18 print("剩余的内容:")
    19 print(s.read())

    以上代执行输出的结果为:

    12
    s中的内容为: Hello World
    This is a test
    
    五个字符的内容:
    Hello
    剩余的内容:
    
    World

    io.StringIO 只能用于文本。如果你要操作二进制数据,要使用io.BytesIO 类来代替。比如:

    1 import io
    2 s = io.BytesIO()
    3 s.write(b'binary data')
    4 data = s.getvalue()
    5 print("数据类型:", type(data))
    6 print("data的值:", data)

    以上代执行输出的结果为:

    数据类型: <class 'bytes'>
    data的值: b'binary data

    注意:

      需要注意的是, StringIO 和BytesIO 实例并没有正确的整数类型的文件描述符。因此,它们不能在那些需要使用真实的系统级文件如文件,管道或者是套接字的程序中使用

    读写压缩文件

    问题:

      你想读写一个gzip 或bz2 格式的压缩文件

    解决方案:

      gzip 和bz2 模块可以很容易的处理这些文件。两个模块都为open() 函数提供了另外的实现来解决这个问题。比如,为了以文本形式读取压缩文件,可以这样做:

     1 import gzip
     2 import bz2
     3 import os
     4 
     5 #打开/tmp/bashrc的文件并获取内容
     6 with open('/etc/bashrc', 'rb') as f:
     7     content = f.read()
     8 
     9 #使用gzip打开文件,xb如果文件存在就报错,不存在创建,把读取的内容写入到文件
    10 try:
    11     f = gzip.open('/tmp/bashrc.gz', 'xb')
    12 except Exception as e:
    13     print('文件已存在~')
    14 else:
    15     f.write(content)
    16 finally:
    17     f.close()
    18 
    19 #获取文件类型
    20 result = os.popen('file /tmp/bashrc.gz').read()
    21 print(result)
    22 
    23 #打开gzip文件并读取内容
    24 with gzip.open('/tmp/bashrc.gz') as f:
    25     content = f.read()
    26 print('bashrc.gz中的内容为:')
    27 print(content.decode('utf-8'))
    28 
    29 #bz2的操作和上面一样..
    30 # with bz2.open('samefile.bz2', 'rb') as f:
    31 #     #f.write(content)
    32 #     #f.read()
    33 #     pass

    以上代执行输出的结果为:

    文件已存在~
    /tmp/bashrc.gz: gzip compressed data, was "bashrc", last modified: Sat Aug  5 00:57:56 2017, max compression
    
    bashrc.gz中的内容为:
    # System-wide .bashrc file for interactive bash(1) shells.
    if [ -z "$PS1" ]; then
       return
    fi
    
    PS1='h:W u$ '
    # Make bash check its window size after a process completes
    shopt -s checkwinsize
    
    [ -r "/etc/bashrc_$TERM_PROGRAM" ] && . "/etc/bashrc_$TERM_PROGRAM"
    alias cls='clear'
    alias ll='ls -l'

    读取二进制数据到可变缓冲区中

    问题:

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

    解决方案:

      为了读取数据到一个可变数组中,使用文件对象的readinto() 方法。比如:

     1 import os.path
     2 
     3 def read_into_buffer(filename):
     4     buf = bytearray(os.path.getsize(filename))
     5     with open(filename, 'rb') as f:
     6         f.readinto(buf)
     7     return buf
     8 
     9 #创建文件并写入内容
    10 with open('sample.bin', 'wb') as f:
    11     f.write(b'Hello World')
    12 
    13 #获取buf的内容
    14 buf = read_into_buffer('sample.bin')
    15 
    16 #修改缓存文件中五个长度的值
    17 print("未修改文件中的前五个值:", buf[:5])
    18 buf[:5] = b'hello'
    19 print('修改bu文件以后的值:',buf)
    20 
    21 #再次打开文件并把修改的数据放入到里面
    22 with open('sample.bin', 'wb') as f:
    23     f.write(buf)

    以上代执行输出的结果为:

    未修改文件中的前五个值: bytearray(b'Hello')
    修改bu文件以后的值: bytearray(b'hello World')

    内存映射的二进制文件

    问题:

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

    解决方案:

      使用mmap 模块来内存映射文件。下面是一个工具函数,向你演示了如何打开一个文件并以一种便捷方式内存映射这个文件

     1 import os
     2 import mmap
     3 
     4 #使用mmap模块内存映射文件
     5 def memory_map(filename, access=mmap.ACCESS_WRITE):
     6     size = os.path.getsize(filename)
     7     fd = os.open(filename, os.O_RDWR)
     8     return mmap.mmap(fd, size , access=access)
     9 
    10 
    11 #以创建并且内容不为空的文件
    12 size = 1000000
    13 with open('data', 'wb') as f:
    14     f.seek(size-1)
    15     f.write(b'x00')
    16 
    17 #memory_map()函数内存映射
    18 print('内存映射'.center(30, '*'))
    19 m = memory_map('data')
    20 print(len(m))
    21 print(m[:10])
    22 #重新赋值
    23 m[:11] = b'hello world'
    24 m.close()
    25 
    26 #获取内存映射的内容
    27 print('获取内存映射的内容:'.center(30, '-'))
    28 with open('data', 'rb') as f:
    29     print(f.read(11))

    以上代执行输出的结果为:

    *************内存映射*************
    1000000
    b'x00x00x00x00x00x00x00x00x00x00'
    ----------获取内存映射的内容:----------
    b'hello world'

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

    文件路径名的操作

    问题:

      你需要使用路径名来获取文件名,目录名,绝对路径等等

    解决方案:

      使用os.path 模块中的函数来操作路径名。下面是一个交互式例子来演示一些关键的特性:

     1 import os
     2 path = '/etc/passwd/passwd.bak'
     3 
     4 #获取文件名
     5 basename = os.path.basename(path)
     6 print('file name:', basename)
     7 
     8 #获取目录路径
     9 dirname = os.path.dirname(path)
    10 print("dirname:", dirname)
    11 
    12 #做多个目录拼接在拼接上文件
    13 path_join = os.path.join('/tmp/a/b/c', 'd',os.path.basename(path))
    14 print('path join:', path_join)
    15 
    16 #获取当前用户的家目录信息
    17 path = '~/Data/data.csv'
    18 print("user:", os.path.expanduser(path))
    19 
    20 
    21 #获取后缀名
    22 split_path = os.path.splitext(path)
    23 print("splitext:", split_path)

    以上代执行输出的结果为:

    file name: passwd.bak
    dirname: /etc/passwd
    path join: /tmp/a/b/c/d/passwd.bak
    user: /Users/demon/Data/data.csv
    split: ('~/Data/data', '.csv')

    测试文件是否存在

    问题:

      你想测试一个文件或目录是否存在

    解决方案:

      使用os.path 模块来测试一个文件或目录是否存在。比如:

     1 import os
     2 
     3 #判断/etc/passwd是否存在
     4 print('/etc/passwd exists:', os.path.exists('/etc/passwd'))
     5 
     6 #判断/tmp/spam是否存在
     7 print('/tmp/spam exists:', os.path.exists('/tmp/spam'))
     8 
     9 #判断/etc/passwd是否为一个文件
    10 print('/etc/passwd is file:', os.path.isfile('/etc/passwd'))
    11 
    12 #判断/tmp是否为一个目录
    13 print('/tmp is directory:', os.path.isdir('/tmp'))
    14 
    15 #判断/usr/local/bin/python3是否为一个链接文件
    16 print('/usr/local/bin/python3 is link:', os.path.islink('/usr/local/bin/python3'))
    17 
    18 #获取软连接的绝对路径
    19 print('/usr/local/bin/python3 real directory:', os.path.realpath('/usr/local/bin/python3'))
    20 
    21 #获取文件的大小
    22 print('file size:', os.path.getsize('/etc/passwd'))
    23 
    24 #文件的修改时间
    25 print('file mtime:', os.path.getmtime('/etc/passwd'))
    26 
    27 #文件的改变时间
    28 import time
    29 print('file ctime:', time.ctime(os.path.getctime('/etc/passwd')))

    以上代执行输出的结果为:

    /etc/passwd exists: True
    /tmp/spam exists: False
    /etc/passwd is file: True
    /tmp is directory: True
    /usr/local/bin/python3 is link: True
    /usr/local/bin/python3 real directory: /Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6
    file size: 5925
    file mtime: 1456440624.0
    file ctime: Sat Aug  6 07:46:53 2016

    获取文件夹中的文件列表

    问题:

      你想获取文件系统中某个目录下的所有文件列表

    解决方法:  

      使用os.listdir() 函数来获取某个目录中的文件列表:

     1 import os
     2 
     3 #获取当前目录下的文件
     4 # names = os.listdir('somedir')
     5 
     6 #获取所有的文件
     7 path = '/tmp'
     8 #列表推到式的写法
     9 names = [name for name in os.listdir(path) if os.path.isfile(os.path.join(path,name))]
    10 print('所有文件名的列表:', names)
    11 
    12 #另外一种通过高阶函数filter
    13 filter_names = list(filter(lambda name:os.path.isfile(os.path.join(path,name)),os.listdir(path)))
    14 print('filter的所有文件名列表:', filter_names)
    15 
    16 
    17 #获取所有的目录
    18 dirnames = list(filter(lambda name:os.path.isdir(os.path.join(path,name)),os.listdir(path)))
    19 print('所有目录的名称 :', dirnames)
    20 
    21 #过滤内容,查找当前目录下的所有以.log结尾或者.gz结尾的文件
    22 files = [name for name in names if name.endswith(('log','gz'))]
    23 print("查找目录下以log或者gz结尾的文件", files)
    24 
    25 #另外一种写法
    26 from fnmatch import fnmatch
    27 fnmatch_files = [name for name in names if fnmatch(name, '*.log')]
    28 print('另外一种查找以log结尾的文件:', fnmatch_files)

    以上代执行输出的结果为:

    所有文件名的列表: ['.adobeLockFile', '.keystone_install_lock', 'adobegc.log', 'AlTest1.err', 'AlTest1.out', 'bashrc.gz', 'com.adobe.acrobat.rna.AcroCefBrowserLock', 'escalatelantern.ico', 'swtag.log']
    filter的所有文件名列表: ['.adobeLockFile', '.keystone_install_lock', 'adobegc.log', 'AlTest1.err', 'AlTest1.out', 'bashrc.gz', 'com.adobe.acrobat.rna.AcroCefBrowserLock', 'escalatelantern.ico', 'swtag.log']
    所有目录的名称 : ['com.apple.launchd.18kY10uuPh', 'com.apple.launchd.dVLT4hIllt']
    查找目录下以log或者gz结尾的文件 ['adobegc.log', 'bashrc.gz', 'swtag.log']
    另外一种查找以log结尾的文件: ['adobegc.log', 'swtag.log']

    打印不合法的文件名

    问题:

      你的程序获取了一个目录中的文件名列表,但是当它试着去打印文件名的时候程序崩溃,出现了UnicodeEncodeError 异常和一条奇怪的消息—— surrogates not allowed

    解决方案:

      当打印未知的文件名时,使用下面的方法可以避免这样的错误:

     1 import sys
     2 
     3 names = ['spam.py', 'budce4d.txt', 'foo.txt']
     4 
     5 def bad_filename(filename):
     6     return repr(filename)[1:-1]
     7 
     8 print('第一个版本的错误处理:'.center(40, '*'))
     9 for filename in names:
    10     try:
    11         print(filename)
    12     except UnicodeEncodeError:
    13         print(bad_filename(filename))
    14 
    15 
    16 #另外一个版本的解决办法
    17 def bad_filename(filename):
    18     #忽略编码的错误,sys.getfilesystemencoding是获取当前系统的编码
    19     temp = filename.encode(sys.getfilesystemencoding(), errors='surrogateescape')
    20     return temp.decode('latin-1')
    21 
    22 print('第二个版本的错误处理:'.center(40, '-'))
    23 for filename in names:
    24     try:
    25         print(filename)
    26     except UnicodeEncodeError:
    27         print(bad_filename(filename))

    以上代执行输出的结果为:

    **************第一个版本的错误处理:***************
    spam.py
    budce4d.txt
    foo.txt
    --------------第二个版本的错误处理:---------------
    spam.py
    bäd.txt
    foo.txt

    序列化Python 对象

    问题:

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

    解决方案: 

      对于序列化最普遍的做法就是使用pickle 模块。为了将一个对象保存到一个文件中,可以这样做:

     1 import pickle
     2 
     3 '''
     4 data = 'same python object....'
     5 #序列化对象到文件存储中
     6 f = open('somefile', 'wb')
     7 pickle.dump(data, f)
     8 '''
     9 
    10 #实例
    11 #利用pickle分别把列表 字符串 字典类型的数据写入到/tmp/test文件中
    12 f = open('/tmp/test', 'wb')
    13 pickle.dump([1, 2, 3, 4], f)
    14 pickle.dump('Hello World', f)
    15 pickle.dump({'name':'demon'}, f)
    16 print('写入完毕')
    17 f.close()
    18 
    19 #读取文件中的内容
    20 f = open('/tmp/test', 'rb')
    21 print(pickle.load(f))
    22 print(pickle.load(f))
    23 print(pickle.load(f))

    以上代执行输出的结果为:

    写入完毕
    [1, 2, 3, 4]
    Hello World
    {'name': 'demon'}
  • 相关阅读:
    年末反思
    Flink运行时架构
    Phoenix 启动报错:Error: ERROR 726 (43M10): Inconsistent namespace mapping properties. Cannot initiate connection as SYSTEM:CATALOG is found but client does not have phoenix.schema.
    Clickhouse学习
    Flink简单认识
    IDEA无法pull代码到本地,Can't Update No tracked branch configured for branch master or the branch doesn't exist.
    第1章 计算机系统漫游
    简单的 Shell 脚本入门教程
    开源≠免费 常见开源协议介绍
    MySQL 视图
  • 原文地址:https://www.cnblogs.com/demon89/p/7288349.html
Copyright © 2011-2022 走看看