百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python文件操作的实用编程技巧总结,建议收藏学习

off999 2024-09-27 13:57 65 浏览 0 评论

这个问题看似简单,但是由于py2 和 py3 的巨大差异导致我们依然要深入研究一下。

那么 python2 和 python3 的什么区别导致了这种差异的发生呢?

有需要Python学习资料的小伙伴吗?小编整理【一套Python资料、源码和PDF】,感兴趣者可以关注小编后私信学习资料(是关注后私信哦)反正闲着也是闲着呢,不如学点东西啦

答:python2 和 python3 之间字符串的语意发生了变化

python2 有两种字符串的类型:

(1)str

表面上看是字符串,但是实际上是抽象的一串连续的字节(字符串中每个字符都是一个字节)

(2)unicode

这个类型是在更多不同的语言加入以后不得不进行调整的,不再用一个字节表示一个字符,但是,我们进行文件操作的时候是不支持直接将多个字节一下子存储进去的,我们必须将其转化成某种单个字节的编码再进行存储操作

示例代码:

将文字编码:

In [1]: a = u'你好世界'
In [2]: a.encode('utf8')
Out[2]: '\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c'
In [3]: a.encode('gbk')
Out[3]: '\xc4\xe3\xba\xc3\xca\xc0\xbd\xe7'

可以看到 utf-8 使用的字节比Gbk多

将文字解码:

注意:这里编码和解码一定要对应,否则会出现乱码。

代码示例:

In [5]: '\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c'.decode('gbk')
Out[5]: u'\u6d63\u72b2\u30bd\u6d93\u682b\u666b'
In [6]: print u'\u6d63\u72b2\u30bd\u6d93\u682b\u666b'
浣犲ソ涓栫晫

代码示例:

In [8]: '\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c'.decode('utf8')
Out[8]: u'\u4f60\u597d\u4e16\u754c'
In [9]: print u'\u4f60\u597d\u4e16\u754c'
你好世界

1.python2 的文本读写

文本就是Unicode 字符串,我们写入文件前先要对其选择一个方式进行编码,我们读取文件的时候也要对其进行先解码,将其换原成 unicode 。

文本的写入:

f = open('test.txt','w')
s = u'你好世界'
f.write(s.encode('utf8'))

文本的读出:

In [8]: f = open('test.txt','r')
In [9]: t = f.read()
In [10]: t
Out[10]: '\xe4\xbd\xa0\xe5\xa5\xbd\xe4\xb8\x96\xe7\x95\x8c'

可以看到这样读出来的都是字节码

我们必须要进行转化:

In [11]: t.decode('utf8')
Out[11]: u'\u4f60\u597d\u4e16\u754c'
In [12]: print u'\u4f60\u597d\u4e16\u754c'
你好世界

2.python3 的文本读写

python3 对字符串的支持更加清晰合理,unicode 就是 python3 中的 str 而 str 就是python3 中的 byte

就比如说,python2 中字符串前面加一个u 才代表 unicode 字符串但是 python3 什么都不用加直接就是,反倒是如果想成为一个 byte 字符串要加 b

python3 的读写可以指定一个参数 encoding = ‘’ 自动的进行编解码

文本的写入:

f = open('test.txt','w',encoding = 'utf8')
f.write("国庆快乐")

文本的读出:

f = open('test.txt','r',encoding='utf8')
t = f.read()
print (t)

二、如何处理二进制文件

wav 是音频问价,前44字节是文件的头信息,我们可以尝试将其读出来

In [6]: f = open('test.wav','rb')
In [7]: info = f.read(44)
In [8]: info
Out[8]: 'RIFFt\x9b\x0b\x00WAVEfmt \x10\x00\x00\x00\x01\x00\x02\x00\x11+\x00\x00D\xac\x00\x00\x04\x00\x10\x00dataP\x9b\x0b\x00'

那么我们如何将其解析出来呢?

我们可以使用 struct 这个库中的unpack 方法

举个例子:

h 是一个 short 的意思

import struct
print struct.unpack('h','\x01\x02')//小端序
print '\n'
print struct.unpack('>h','\x01\x02')//大端序
(513,)//--------->2x256+1
(258,)//--------->1x256+2

比如我们的音频文件的 22-24 字节是声道数,于是我们就能使用这个函数将其解析出来

代码示例:

import struct
f = open('test.wav','rb')
info = f.read(44)
print struct.unpack('h',info[22:24])

结果:

(2,)

说明这个音频文件是双声道

再比如我们想读音频文件的采样频率,这个东西是24-28 4个字节

代码示例:

import struct
f = open('test.wav','rb')
info = f.read(44)
print struct.unpack('i',info[24:28])//因为这里是4个字节所以我们就是用的i

结果:

(11025,)

综合实验:

我们现在想读入音频文件的数据部分,并且不能以字符串的形式,因为字符串的形式没法进行输入操作,我们可以将其以每两个字节为一组读入一个buf

我们首先看一下我们的音频的数据有多大:

import array
f = open('test.wav', 'rb')
f.seek(0, 2) # 移动指针的位置
t = f.tell() # 返回指针的位
a = (t-44)/2 # 每两个一组进行分组
print a

a 就是最终的组数

然后我们就创建指定类型大小的Buf,我们把buf初始化,并将44字节以后的输入写入buf

buf = array.array('h',(0 for _ in xrange(a)))
f.seek(44)
f.readinto(buf)

接下来我们对 buf 进行操作,将操作完的结果重新写成另一个文件

info = f.read(44)

for i in xrange(a):

buf[i]/=8

f2 = open('demo.wav','wb')
f2.write(info)
buf.tofile(f2)
f2.close()

以上步骤,我们其实已经将我们的音频声音变成了原来的1/8

代码示例:

# coding=utf-8
import struct
import array
f = open('test.wav', 'rb')
info = f.read(44)
f.seek(0, 2) # 移动指针的位置
t = f.tell() # 返回指针的位置
a = (t-44)/2
buf = array.array('h',(0 for _ in xrange(a)))
f.seek(44)
f.readinto(buf)
for i in xrange(a):
 buf[i]/=8
f2 = open('demo.wav','wb')
f2.write(info)
buf.tofile(f2)
f2.close()

三、如何设置文件的缓冲

将文件写入硬件设备的时候是按照块进行写入的,每个块有固定的大小,也就是说,进行一次写入操作的时间是固定的,不管你有没有把块填满,因此如果没有缓冲,就会在块不满的情况下进行写入,导致次数过多时间过长,于是我们需要设置文件缓冲。

缓冲又分为全缓冲和行缓冲,一般文件的缓冲就是全缓冲,意思就是填满一个就释放一个,而行缓冲就是遇到换行符就释放。

当然并不是所有的设备都需要缓冲的,串口设备我们就希望能即时发送,于是我们不设置缓冲区

1.检验缓冲区大小实验:

ipython :

In [13]: f = open(‘demo.txt’,’w’)

In [14]: f.write(‘abc’)

In [15]: f.write(‘+’*4093)

In [16]: f.write(‘-‘)

另一个终端:

$ tail -f demo.txt

14、15 命令执行以后 tail 都没反应,直到16命令执行,在tail 后面输出了 abc和 4093个*,可见缓冲区的大小是4096字节

2.修改默认缓冲区的大小

(1)全缓冲:

open 函数 有一个 buffering 的选项可以设置缓冲区大小,我们设置为大于一的整数

f = open('demo.txt','w',buffering = 2048)

(2)行缓冲:

将 buffering 设置为1

f = open('demo.txt','w',buffering = 1)

(3)无缓冲:

将 buffering 设置为0

f = open('demo.txt','w',buffering = 0)

四、如何将文件映射到内存

需求:

1.在访问二进制文件的时候,希望把文件映射到内存空间,实现随机访问

2.嵌入式设备中,寄存器被编址到内存地址空间,我们可以映射 /dev/mem 的某些范围,来操纵这些寄存器

3.如果多个进程映射同一个文件,还能实现进程通信

使用 mmap.mmap()

通过下面这条命令创建一个1M的全0文件:

dd if=/dev/zero of=demo.bin bs=1024 count=1024

使用 od -x 查看,发现的确是全0

od -x demo.bin

0000000 0000 0000 0000 0000 0000 0000 0000 0000

*

4000000

我们获取文件描述符

示例代码:

f = open('demo.bin','r+b')
print f.fileno()

结果:

我们将整个文件映射到变量m

m = mmap.mmap(num,0,mmap.ACCESS_WRITE) # 这里的0表示的是全部文件

我们看一下内容:

In [10]: m[100]
Out[10]: '\x00'

修改:

In [11]: m[100] = '\x08'

查看修改后的内容

In [12]: m[99:120]
Out[12]: '\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

实际上在这种情况下文件已经被修改。

我们还可以跳过整数倍的页的大小对文件进行修改(页的概念来源于操作系统,如果不了解可以去查一下)

m = mmap.mmap(num,mmap.PAGESIZE*8,mmap.ACCESS_WRITE,offset = mmap.PAGESIZE*4)

五、如何访问文件的状态

在某些项目中我们需要获取文件的状态,

比如:

(1)文件类型

(2)文件权限

(3)文件最后修改时间

(4)文件的大小

方法一:系统调用

1.os.stat()

2.os.lstat()

它与os.stat 的区别在于它不跟随符号链接文件,意思就是lstat 拿到的是快捷方式的属性,而stat 拿到的是原始文件的属性

3.os.fstat()

这个函数和上面两个函数的区别是这个函数传入的参数是文件描述符,而不是上面两个参数传入的路径。

示例代码:

In [3]: import os
In [4]: os.stat('demo.bin')
Out[4]: posix.stat_result(st_mode=33188, st_ino=264254, st_dev=2049, st_nlink=1, st_uid=0, st_gid=0, st_size=1048576, st_atime=1538365252, st_mtime=1538364797, st_ctime=1538364797)

查看文件的类型:

文件的类型就存储在 st_mode 里面,我们需要将其解析

In [15]: import os
In [16]: s = os.stat('demo.bin')
In [17]: import stat
In [18]: stat.S_ISDIR(s.st_mode)
Out[18]: False

查看文件的权限

In [19]: s.st_mode & stat.S_IRUSR
Out[19]: 256

只要这个返回值大于0就说明有用户读的权限

In [20]: s.st_mode & stat.S_IXUSR
Out[20]: 0

可见用户的执行权限是0

查看文件的最后访问时间:

In [25]: import time
In [26]: time.localtime(s.st_atime)
Out[26]: time.struct_time(tm_year=2018, tm_mon=10, tm_mday=1, tm_hour=11, tm_min=40, tm_sec=52, tm_wday=0, tm_yday=274, tm_isdst=0)

方法二:快捷函数

快捷函数在底层实现上是利用的是系统函数,但是会让你操作起来更加方便

判断文件类型:

In [27]: os.path.isdir('demo.bin')
Out[27]: False
In [28]: os.path.isfile('demo.bin')
Out[28]: True

判断文件最后访问时间:

In [32]: time.localtime(os.path.getatime('demo.bin'))
Out[32]: time.struct_time(tm_year=2018, tm_mon=10, tm_mday=1, tm_hour=11, tm_min=40, tm_sec=52, tm_wday=0, tm_yday=274, tm_isdst=0)

六、如何使用临时文件:

比如我们采集数据进行分析,但是我们只需要保存结果,我们采集的数据如果常驻内存就会让电脑崩溃,于是我们将这个数据放在临时文件中(外部存储),在文件关闭后将被删除

示例代码:

In [15]: from tempfile import TemporaryFile,NamedTemporaryFile
In [16]: f = TemporaryFile()
In [17]: f.write('abc'*10000)
In [18]: f.seek(0)
In [19]: f.read(100)
Out[19]: 'abcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabcabca'

这个临时文件在系统中是找不到的,如果我们想创建一个能在文件系统中看到的临时文件,我们就用NamedTemporaryFile

示例代码:

我们能看到文件路径

In [20]: nte = NamedTemporaryFile()
In [21]: nte.name
Out[21]: 'c:\\users\\k0rz3n\\appdata\\local\\temp\\tmpob51yb'

如果我们重新创建一个文件的话,原来的文件就会被关闭,关闭以后临时文件就会被自动删除,如果我们不想让他删除,我们在创建的时候就要设置一个参数

nte = NamedTemporaryFile(delete = False)

有需要Python学习资料的小伙伴吗?小编整理【一套Python资料、源码和PDF】,感兴趣者可以关注小编后私信学习资料(是关注后私信哦)反正闲着也是闲着呢,不如学点东西啦

相关推荐

Linux 网络协议栈_linux网络协议栈

前言;更多学习资料(包含视频、技术学习路线图谱、文档等)后台私信《资料》免费领取技术点包含了C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,Z...

揭秘 BPF map 前生今世_bpfdm

1.前言众所周知,map可用于内核BPF程序和用户应用程序之间实现双向的数据交换,为BPF技术中的重要基础数据结构。在BPF程序中可以通过声明structbpf_map_def...

教你简单 提取fmpeg 视频,音频,字幕 方法

ffmpeg提取视频,音频,字幕方法(HowtoExtractVideo,Audio,SubtitlefromOriginalVideo?)1.提取视频(ExtractVi...

Linux内核原理到代码详解《内核视频教程》

Linux内核原理-进程入门进程进程不仅仅是一段可执行程序的代码,通常进程还包括其他资源,比如打开的文件,挂起的信号,内核内部的数据结构,处理器状态,内存地址空间,或多个执行线程,存放全局变量的数据段...

Linux C Socket UDP编程详解及实例分享

1、UDP网络编程主要流程UDP协议的程序设计框架,客户端和服务器之间的差别在于服务器必须使用bind()函数来绑定侦听的本地UDP端口,而客户端则可以不进行绑定,直接发送到服务器地址的某个端口地址。...

libevent源码分析之bufferevent使用详解

libevent的bufferevent在event的基础上自己维护了一个buffer,这样的话,就不需要再自己管理一个buffer了。先看看structbufferevent这个结构体struct...

一次解决Linux内核内存泄漏实战全过程

什么是内存泄漏:程序向系统申请内存,使用完不需要之后,不释放内存还给系统回收,造成申请的内存被浪费.发现系统中内存使用量随着时间的流逝,消耗的越来越多,例如下图所示:接下来的排查思路是:1.监控系统中...

彻底搞清楚内存泄漏的原因,如何避免内存泄漏,如何定位内存泄漏

作为C/C++开发人员,内存泄漏是最容易遇到的问题之一,这是由C/C++语言的特性引起的。C/C++语言与其他语言不同,需要开发者去申请和释放内存,即需要开发者去管理内存,如果内存使用不当,就容易造成...

linux网络编程常见API详解_linux网络编程视频教程

Linux网络编程API函数初步剖析今天我们来分析一下前几篇博文中提到的网络编程中几个核心的API,探究一下当我们调用每个API时,内核中具体做了哪些准备和初始化工作。1、socket(family...

Linux下C++访问web—使用libcurl库调用http接口发送解析json数据

一、背景这两天由于一些原因研究了研究如何在客户端C++代码中调用web服务端接口,需要访问url,并传入json数据,拿到返回值,并解析。 现在的情形是远程服务端的接口参数和返回类型都是json的字符...

平衡感知调节:“系统如人” 视角下的架构设计与业务稳定之道

在今天这个到处都是数字化的时代,系统可不是一堆冷冰冰的代码。它就像一个活生生的“数字人”,没了它,业务根本转不起来。总说“技术要为业务服务”,但实际操作起来问题不少:系统怎么才能快速响应业务需求?...

谈谈分布式文件系统下的本地缓存_什么是分布式文件存储

在分布式文件系统中,为了提高系统的性能,常常会引入不同类型的缓存存储系统(算法优化所带来的的效果可能远远不如缓存带来的优化效果)。在软件中缓存存储系统一般可分为了两类:一、分布式缓存,例如:Memca...

进程间通信之信号量semaphore--linux内核剖析

什么是信号量信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。信号量的值为正的时候,说明它空闲。所测试的线程可以锁定而使用它。若为0,说明它被占用,测试的线程要进入睡眠...

Qt编写推流程序/支持webrtc265/从此不用再转码/打开新世界的大门

一、前言在推流领域,尤其是监控行业,现在主流设备基本上都是265格式的视频流,想要在网页上直接显示监控流,之前的方案是,要么转成hls,要么魔改支持265格式的flv,要么265转成264,如果要追求...

30 分钟搞定 SpringBoot 视频推拉流!实战避坑指南

30分钟搞定SpringBoot视频推拉流!实战避坑指南在音视频开发领域,SpringBoot凭借其快速开发特性,成为很多开发者实现视频推拉流功能的首选框架。但实际开发中,从环境搭建到流处理优...

取消回复欢迎 发表评论: