1.文件

__author__ = 'Kaiming'


# P1 打开文件、读文件、关闭文件的典型方法

try:
    f = open('./test.txt', 'r')
    print(f.read())

finally:
    if f:
        f.close()


# P2 推荐的简洁写法,不必显式的关闭文件描述符
# open返回的对象在python中称作file-like 对象,可以是字节流、网络流、自定义流等
with open('./test.txt', 'r') as f:
    # 按行读取
    for line in f.readlines():
        print(line.strip())

# P3 直接读取二级制的图片、视频文件

# with open('D:/banner.jpg','rb') as f2:
#     for line in f2.readlines():
#         print(line.strip())


# P4 可以指定编码读取相应的数据,还可以忽略非法编码

with open('./test.txt', 'r', encoding='gbk', errors='ignore') as f3:
    for line in f3.readlines():
        print(line.strip())

# P5 写文件的流程和读文件是一样的 代开文件、写入内容、关闭文件

# 'r'   open for reading (default)
# 'w'   open for writing, truncating the file first
# 'x'   open for exclusive creation, failing if the file already exists
# 'a'   open for writing, appending to the end of the file if it exists
# 'b'   binary mode
# 't'   text mode (default)
# '+'   open a disk file for updating (reading and writing)
# 'U'   universal newlines mode (deprecated)
# with open('D:/test12.txt','a+') as f4:
#     for line in f4.readlines():
#         print(line.strip())
#     f4.write('a new line2!')

2.字节流和字符流

# P6 StringIO和BytesIO分别对字符串和二进制内容进行内存的读写


from io import StringIO # 类似java里面的字符流

f1 = StringIO()
f1.write('Hello World!')
s = f1.getvalue()  # 用getvalue才能获取值,不能用readlines()
print(s)

from io import BytesIO #类似java里面的字节流,处理二进制数据
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
f.read()        # 可以用read方法像读文件一样读取

3.os模块完成一个简易文件查询系统

__author__ = 'Kaiming'

import os
import pdb

class IO_dir(object):
    flag = False  # 类变量,用于在类全局内保存是否找到相应的文件

    def dir_l(self):
        '用于显示当前目录下所有文件和目录'
        list_all = os.listdir()  # listdir包括所有文件和目录,不加任何参数默认是当前目录下
        print('当前目录下的所有目录如下:')
        # 这里os.path.isdir不需要join,因为当前目录本来就有x
        list_dirs = [x for x in list_all if os.path.isdir(x)]
        print(list_dirs)

        print('当前目录下的所有文件如下:')
        list_files = [x for x in list_all if os.path.isfile(x)]
        print(list_files)

    def search_file(self, file_name, path):
        '用于在当前目录以及子目录下搜索相关的文件,并打印出它的路径,如果当前目录找到了,则不再进子目录寻找'
        file_list = []  # 如果是文件就直接放入文件list
        dir_list = []  # 如果是目录就直接放入目录list
        for x in os.listdir(path):
            # !!!这一句非常重要,因为isfile的判断需要完整的路径名,如果不加这句,isfile的参数只是单纯的一个名字,就会全部返回False
            # pdb.set_trace()     #调试 
            fullpath = os.path.join(path, x)        # path方法和x的名字连接在一起称为一个完整的路径
            if os.path.isfile(fullpath):
                file_list.append(x)
            else:
                dir_list.append(x)




        if file_name not in file_list:
            if len(dir_list) == 0:
                pass  # 如果当前目录找不到,并且也没子目录了,就可以到函数末尾了,不需要修改flag的值
            else:  # 当前目录没找到,子目录中寻找
                for child_dir in dir_list:      #在每个dir_list中寻找
                    if child_dir == '__pycache__':  # __pycache__是代码产生的二进制文件信息,因此不考虑对其进行搜索
                        return False
                    # 更新最新的路径,将要查找的子目录更新到child_path,切勿join到path,否则path目录下其他目录就无法被遍历。因为for循环每次都执行path.join。
                    child_path = os.path.join(path, child_dir)  
                    self.search_file(file_name, child_path)

        else:  # 如果找到文件
            print('[' + file_name + ']已经找到!')
            print('[' + file_name + ']的相对路径是:' + os.path.join(path, file_name))
            self.flag = True

        return self.flag

    def input_str(self):
        '用于接收用户的输入'
        print('请输入操作命令:')
        ops = str(input())
        return ops


t = IO_dir()    # 创建类实例
print('欢迎使用简易目录文件查看系统,退出系统请输入:exit')
print('------------------------------------------帮助说明------------------------------------------------')
print('(1)dir -l:查看当前目录下(执行该代码处)所有文件和目录')
print('(2)输入名字,会直接在当前目录下以及所有子目录下查找文件名包含指定字符串的文件(只搜索一个),并打印出相对路径,不支持搜索目录!')
print('------------------------------------------END----------------------------------------------------')

ops = t.input_str()
while ops != 'exit':
    if ops == 'dir -l':
        t.dir_l()
    else:
        flag = t.search_file(ops, '.')  # 其他输入内容均看成是查找
        if flag is False:
            print('很遗憾,没有找到相应的文件!')
    ops = t.input_str()

print('感谢使用,再见!')

4.序列化(dump)和反序列化(pickle)

4.1 基本使用方法

__author__ = 'Kaiming'


# 反序列化即pickle(腌制)

import pickle

# dumps(object)将对象序列化

lista = ["mingyue", "jishi", "you"]

listb = pickle.dumps(lista)
print(listb)

# loads(string) 将对象原样恢复,丙炔对象类型也恢复为原来的格式

listc = pickle.loads(listb)
print(listc)


# dump(object,file),将对象存储到文件里面序列化
group1 = ('a', 'b', 'c')
f1 = open('store.txt', 'wb')
pickle.dump(group1, f1, True)
f1.close()


# load(object,file)将dump()存储的文件里面的数据恢复
f2 = open('store.txt', 'rb')
t = pickle.load(f2)
print(t)
f2.close()

4.2 json和python对象互相转化

__author__ = 'Kaiming'

import json

# 序列化pickle使用局限比较多,一般涉及传输的时候都序列化成json比较好
# dumps()方法返回一个str,内容就是标准的JSON。类似的,dump()方法可以直接把JSON写入一个file-like Object。

# 序列化 通过dumps将python对象序列成一个json对象(json对象可以理解为一个字符串)
d = dict(name='Bob', age=20, score=80)
print(json.dumps(d))


# 反序列化,通过loads将json对象反序列化成一个dict对象,注意json对象里面的字符串都用双引号

json_str = '{"name":"Jack","age":18,"score":88}'
print(json.loads(json_str))


# 对类对象进行序列化操作

# 需要一个转换函数将类转化成dict对象(如果没有__slot__变量的可以用另外一种方法)
class Student(object):
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score


s = Student('Bob', 20, 88)


def student2dict(std):
    return {
        'name': std.name,
        'age': std.age,
        'score': std.score

    }


print(json.dumps(s, default=student2dict))

# 偷懒方法,一般没有__slot__的类都可以使用这种偷懒的方法
print(json.dumps(s, default=lambda obj: obj.__dict__))


# 把类json对象反序列成类对象
def dict2student(d):
    return Student(d['name'], d['age'], d['score'])


print(json.loads(json_str, object_hook=dict2student))