Python:Day5:python文件操作

文件操作

一 介绍

计算机系统分为:计算机硬件,操作系统,应用程序三部分。

我们用python或其他语言编写的应用程序若想要把数据永久保存下来,必须要保存于硬盘中,这就涉及到应用程序要操作硬件,众所周知,应用程序是无法直接操作硬件的,这就用到了操作系统。操作系统把复杂的硬件操作封装成简单的接口给用户/应用程序使用,其中文件就是操作系统提供给应用程序来操作硬盘虚拟概念,用户或应用程序通过操作文件,可以将自己的数据永久保存下来。

有了文件的概念,我们无需再去考虑操作硬盘的细节,只需要关注操作文件的流程:

#1. 打开文件,得到文件句柄并赋值给一个变量
#2. 通过句柄对文件进行操作
#3. 关闭文件

二 在python中

#1. 打开文件,得到文件句柄并赋值给一个变量
f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r

#2. 通过句柄对文件进行操作
data=f.read()

#3. 关闭文件
f.close()

三 f=open('a.txt','r')的过程分析

#1、由应用程序向操作系统发起系统调用open(...)

#2、操作系统打开该文件,并返回一个文件句柄给应用程序

#3、应用程序将文件句柄赋值给变量f

四 强调!!!

with方法打开文件不用close()见下:

 1 #强调第一点:
 2 打开一个文件包含两部分资源:操作系统级打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为:
 3 1、f.close() #回收操作系统级打开的文件
 4 2、del f #回收应用程序级的变量
 5 
 6 其中del f一定要发生在f.close()之后,否则就会导致操作系统打开的文件还没有关闭,白白占用资源,
 7 而python自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close()
 8 
 9 虽然我这么说,但是很多同学还是会很不要脸地忘记f.close(),对于这些不长脑子的同学,我们推荐傻瓜式操作方式:使用with关键字来帮我们管理上下文
10 with open('a.txt','w') as f:
11     pass
12  
13 with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
14     data=read_f.read()
15     write_f.write(data)
强调第一点:资源回收
1 #强调第二点:
2 f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-83 这就用到了上节课讲的字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。
4 
5 f=open('a.txt','r',encoding='utf-8')
强调第二点:字符编码

五 python2中的file与open

#首先在python3中操作文件只有一种选择,那就是open()

#而在python2中则有两种方式:file()与open()
两者都能够打开文件,对文件进行操作,也具有相似的用法和参数,但是,这两种文件打开方式有本质的区别,file为文件类,用file()来打开文件,相当于这是在构造文件类,而用open()打开文件,是用python的内建函数来操作,我们一般使用open()打开文件进行操作,而用file当做一个类型,比如type(f) is file

打开文件的模式

文件句柄 = open('文件路径', '模式')

 模式可以是以下方式以及他们之间的组合:

#1. 打开文件的模式有(默认为文本模式):
r,只读模式【默认模式,文件必须存在,不存在则抛出异常】
w,只写模式【不可读;不存在则创建;存在则清空内容】
a,只追加写模式【不可读;不存在则创建;存在则只追加内容】

#2. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)
rb 
wb
ab
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码

#3. 了解部分
"+" 表示可以同时读写某个文件
r+, 读写【可读,可写】
w+, 写读【可读,可写】
a+, 写读【可读,可写】


x, 只写模式【不可读;不存在则创建,存在则报错】
x+ ,写读【可读,可写】
xb
 1 # 回车与换行的来龙去脉
 2 http://www.cnblogs.com/linhaifeng/articles/8477592.html
 3 
 4 # U模式
 5 'U' mode is deprecated and will raise an exception in future versions
 6 of Python.  It has no effect in Python 3.  Use newline to control
 7 universal newlines mode.
 8 
 9 # 总结:
10 在python3中使用默认的newline=None即可,换行符无论何种平台统一用\n即可
了解U模式与换行符

操作文件的方法

#掌握
f.read() #读取所有内容,光标移动到文件末尾
f.readline() #读取一行内容,光标移动到第二行首部
f.readlines() #读取每一行内容,存放于列表中

f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符
f.write('1111\n222\n'.encode('utf-8')) #针对b模式的写,需要自己写换行符
f.writelines(['333\n','444\n']) #文件模式
f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式

#了解
f.readable() #文件是否可读
f.writable() #文件是否可读
f.closed #文件是否关闭
f.encoding #如果文件打开模式为b,则没有该属性
f.flush() #立刻将文件内容从内存刷到硬盘
f.name

练习,利用b模式,编写一个cp工具,要求如下:

  1. 既可以拷贝文本又可以拷贝视频,图片等文件

  2. 用户一旦参数错误,打印命令的正确使用方法,如usage: cp source_file target_file

  提示:可以用import sys,然后用sys.argv获取脚本后面跟的参数

1 import sys
2 if len(sys.argv) != 3:
3     print('usage: cp source_file target_file')
4     sys.exit()
5 
6 source_file,target_file=sys.argv[1],sys.argv[2]
7 with open(source_file,'rb') as read_f,open(target_file,'wb') as write_f:
8     for line in read_f:
9         write_f.write(line)
View Code

文件内光标移动

一: read(3):

  1. 文件打开方式为文本模式时,代表读取3个字符

  2. 文件打开方式为b模式时,代表读取3个字节

二: 其余的文件内光标移动都是以字节为单位如seek,tell,truncate

注意:

  1. seek有三种移动方式0,1,2,其中1和2必须在b模式下进行,但无论哪种模式,都是以bytes为单位移动的

  2. truncate是截断文件,所以文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果

1 import time
2 with open('test.txt','rb') as f:
3     f.seek(0,2)
4     while True:
5         line=f.readline()
6         if line:
7             print(line.decode('utf-8'))
8         else:
9             time.sleep(0.2)
练习-基于seek实现tail-f功能

文件的修改

文件的数据是存放于硬盘上的,因而只存在覆盖、不存在修改这么一说,我们平时看到的修改文件,都是模拟出来的效果,具体的说有两种实现方式:

方式一:将硬盘存放的该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,再由内存覆盖到硬盘(word,vim,nodpad++等编辑器)

import os

with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f:
    data=read_f.read() #全部读入内存,如果文件很大,会很卡
    data=data.replace('alex','SB') #在内存中完成修改

    write_f.write(data) #一次性写入新文件

os.remove('a.txt')
os.rename('.a.txt.swap','a.txt') 

方式二:将硬盘存放的该文件的内容一行一行地读入内存,修改完毕就写入新文件,最后用新文件覆盖源文件

import os

with open('a.txt') as read_f,open('.a.txt.swap','w') as write_f:
    for line in read_f:
        line=line.replace('alex','SB')
        write_f.write(line)

os.remove('a.txt')
os.rename('.a.txt.swap','a.txt') 

练习题:

1. 文件a.txt内容:每一行内容分别为商品名字,价钱,个数,求出本次购物花费的总钱数
apple 10 3
tesla 100000 1
mac 3000 2
lenovo 30000 3
chicken 10 3

2. 修改文件内容,把文件中的alex换成sb

 

# 1.函数中return的作用
'''将函数的运行结果返回给调用的对象。'''

# 2.函数中如果有多个return,会是什么效果
'''只执行满足其判定条件的的一个return在本函数中其后面的代码将不再执行'''
# 3.定义一个函数max1,接受的参数类型是数值,最终返回两个数中的最大值
def max1(*args):
    list =[]
    for i in args:
        list.append(i)
    print(list)
    result= max(list)
    print(result)
max1(2,4,6,8,12,)
print('分割线'.center(50,'-'))
# 4.定义一个函数min,接受的参数类型是数值,最终返回两个数中的最小值
def min1(*args):
    list=[]
    for i in args:
        list.append(i)
    print(list)
    result = min(list)
    print(result)
min1(2,8,6,7,3,4,9,1,)
print('分割线'.center(50,'*'))
# 5.定义一个函数add_two 求两个数的和
def add_two(*args):
    result = 0
    for i in args:
        result += i
    print(result)
    return result
add_two(2,3)
print('分割线'.center(50,'-'))
# 6.定义一个函数add_three 在上一题的基础上求三个数的和
def add_three(*args):
    result = 0
    for i in args:
        result+=i
    print(result)
add_three(2,3,9,)
print('分割线'.center(50,'*'))
# 7.将人数平均随机分配到办公室
'''
import random
def people(p_lists,n):
    print(p_lists)
    o_lists = [[] for i in range(n)]
    print(o_lists)
    while len(p_lists)>0:
        ret = len(o_lists)
        for i in range(ret):
            if len(p_lists)>0:
                peo = random.choice(p_lists)
                o_lists[i].append(peo)
                print(o_lists)
                p_lists.remove(peo)
                print(p_lists)
            else:
                break
    print(o_lists)
    return o_lists
p = ['张三', '李四', '王五', '赵六', '陈二狗', '徐发财', '唐倒霉', '派大星', '可爱迷', '范无救', '谢必安']
o= 3
people(p,o)
print('分割线'.center(50,'-'))
'''
# 8.完成一个小型的计算器 计算连个数的加减乘除
def jisuan(a,b,c):
    if c == "+":
        return a + b
    elif c == "-":
        return a - b
    elif c == "*":
        return a * b
    elif c == "/":
        return a / b
print(jisuan(10, 5, "*"))
# 9.完成一个函数,给定三个值。判断你给的值是否可以组成一个三角形(两边之和大于第三边)
def sanjia(a,b,c):
    if a + b -c > 0 and a + c - b > 0 and b +c -a > 0:
        return "ok"
    else:
        return "no"
print(sanjia(10, 15, 14))

# 10.(选做题,这个题难度有点大)
# 定义函数findall,实现对字符串find方法的进一步封装,要求返回符合要求的所有位置的起始下标,
# 如字符串"helloworldhellopythonhelloc++hellojava",需要找出里面所有的"hello"的位置,
# 最后将返回一个元组(0,10,21,29),即将h的下标全部返回出来,而find方法只能返回第一个
def findall(str,s):
    ret = []
    len(s)
    if s == '':
        return ret
    while True:
        index = str.find(s)
        if index != -1:
            if len(ret) != 0:
                ret.append(index+len(s)+ret[-1])
            else:
                ret.append(index)
            str = str[index+len(s):]
        else:
            break
    return tuple(ret)
str1 = 'helloworldhellopythonhelloc++hellojava'
s1 = 'h'
print(findall(str1,s1))

# def findall(string,s):
#     ret = []
#     n = len(s)
#     if s=='':
#         return ret
#     while True:
#         index = string.find(s)
#         if index !=-1:
#             if len(ret)!=0:
#                 ret.append(n+index+ret[-1])
#             else:
#                 ret.append(index)
#             string = string[index+len(s):]
#         else:
#             break
#     return tuple(ret)
# str1 = 'helloworldhellopythonhelloc++hellojava'
# s1 = 'h'
# print(findall(str1,s1))

# def findall(string, s):
#     ret = []
#     n = len(s)
#     if s=='':
#         return ret
#     while True:
#         index = string.find(s)
#         if index != -1:
#             if len(ret)!=0:
#                 ret.append(ret[-1]+index+n)
#             else:
#                 ret.append(index)
#             string = string[index+len(s):]
#         else:
#             break
#     return tuple(ret)
# str1 = 'helloworldhellopythonhelloc++hellojava'
# s1 = 'l'
# print(findall(str1,s1))
import string
def count_letter(str):
    '''求字符串中字母的数量'''
    n = 0
    for i in str:
        # 方法一
        if i.isalpha():
            n+=1
        else:
            continue
        # 方法二
        # string.ascii_letters
        # string.ascii_uppercase

def count_blank():
    '''求字符串中空格的数量'''
    pass
def count_figure():
    '''求字符串中数字的数量'''
    pass
课上笔记
"""
f= open('兰亭集序2.txt','w',encoding='utf8')
f.write('''《兰亭集序》
作者:王羲之
永和九年,岁在癸丑,暮春之初会于会稽山阴只兰亭,俢禊事也。
群贤毕至,少长咸集。
此地有崇山峻岭,茂林修竹,又有清水流急湍,映带左右,引以为流觞曲水,列坐其次。
虽无丝竹管弦之盛,一觞一咏,亦足 以畅叙幽情。
是日也,天朗气清,惠风和畅。仰观宇宙之大,俯察品类之盛,所以游目骋怀,足以极视听之娱,信可乐也。
夫人之相与,俯仰一世。
或取著怀抱,悟言一世之内;
或因寄锁托,放浪形骸之外。
虽趣舍万殊,静噪不同。
当其欣于所遇,暂得于已,快然自足,不知老之将至;
及其所之既倦,情随事迁,感慨系之矣。
当其欣于所遇,暂得于已,快然自足,不知老之将至;及其所之既倦,情随事迁,感慨系之矣。
向之所欣,俯仰之间,已为陈迹,犹不能不以之兴怀,况修短所化,终期于尽!
古人云:“生死亦大矣。”岂不痛哉!
每览昔人兴感之由,若合一契,未尝不临文嗟悼,不能喻之余怀。
固知—死生为虚诞,齐彭殇为妄作。
后之视今,亦犹今之视昔,悲夫!
故列叙时人,录其所属,虽世殊事异,所以兴怀,其致一也。
后之览者,亦将有感于斯文。''')
f.close()
"""

'''
f=open('兰亭集序2.txt','r',encoding='utf8')
# f=open('兰亭集序2.txt',encoding='utf8')     'r' 模式打开可以简写。
content1 = f.read(6)        # 读6个字符
content2 = f.readlines()   # 把读出来的按照行数放到列表对象中,需要for循环读(需要读的行数)
content3 = f.read()       # 接着上一次读的位置读完
# print(content1)
print('_'*50)
# print(content2)
# for i in content2:
#     print(i)
print('_'*50)
# print(content3)
f.close()
'''
"""
# 文件备份实例:
old_file_name = input('请输入你要复制的文件名称:')
index = old_file_name.rfind('.')
PR_file_name = old_file_name[:index]
SF_file_name = old_file_name[index:]
new_file_name = PR_file_name + '[副本]'+SF_file_name
f_old = open(old_file_name,'rb')
f_new = open(new_file_name,'wb')
while True:
    file = f_old.read(1024)
    if len(file) == 0:
        break
    f_new.write(file)
f_old.close()
f_new.close()
"""
'''
# 批量改文件名称
import os
ret = os.listdir()
print(os.listdir())
flag =2
for i in ret:
    if flag==1:
        os.rename(i,'[备份]-'+i)
    elif flag==2:
        num = len('[备份]-')
        new_name = i[num:]
        os.rename(i,new_name)
'''
"""
# 批量复制目录下的所有文件
import os
# 定义一个改名字的函数
def redo_name(a):
    num = a.rfind('.')
    return a[:num] + '副本' + a[num:]
# 定义一个复制文件的函数
def copy_file(b, func):
    f1 = open(b, 'rb')
    f2 = open(func, 'wb')
    while True:
        msg = f1.read(1024)
        if len(msg) == 0:
            break
        f2.write(msg)
    f1.close()
    f2.close()
    return print('复制完成')

file_list = os.listdir()
file_list = tuple(file_list)
for i in file_list:
    redo_name(i)
    copy_file(i, redo_name(i))

# 老师的方法
# import os
# 
# # 获取指定路径的所有文件名字
# dirList = os.listdir()
# funFlag = 0
# # 遍历输出所有文件名字
# for name in dirList:
#     if funFlag == 1:
#         # 以读的方式打开文件
#         oldFile = open(name, 'rb')
#         # 提取文件的后缀
#         fileFlagNum = name.rfind('.')
#         if fileFlagNum > 0:
#             fileFlag = name[fileFlagNum:]
#         # 组织新的文件名字
#         newFileName = name[:fileFlagNum] + '[复件]' + fileFlag
#         # 创建新文件
#         newFile = open(newFileName, 'wb')
#         # 把旧文件中的数据,一行一行的进行复制到新文件中
#         for lineContent in oldFile.readlines():
#             newFile.write(lineContent)
# 
#     elif funFlag == 0:
#         fileFlagNum = name.rfind('.')
#         length = len("[复件]")
#         if fileFlagNum > 0:
#             fileFlag = name[:fileFlagNum]
#         if fileFlag[-length:] == "[复件]":
#             os.remove(name)
"""
文件操作练习题

 

                                                                                                                                                                              Victor

posted @ 2018-07-09 15:25  毛丫头  阅读(149)  评论(0)    收藏  举报