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'}
  • 相关阅读:
    Git 使用juju
    svn Q&A
    ubuntu 常用命令
    java中set的交集、差集、并集的简单实现
    java 读写JSON(一)
    java类型转化之SimpleDateFormat-时间转化
    maven 基本常识以及命令
    maven遇到的问题
    java编程思想,对象导论
    条目5:避免创建不必要的对象
  • 原文地址:https://www.cnblogs.com/demon89/p/7288349.html
Copyright © 2011-2022 走看看