import os

# 操作系统路径分隔符
print(os.sep)

# 操作系统平台名称
print(os.name)

# 获取当前路径
os.getcwd()

# 记录一下这是 zhang yimeng 当时执行后的结果：'C:\\Users\\yimeng.zhang\\Desktop\\Class\\python基础\\python_basic'
# 这是我现在在 windows 电脑上执行的结果：'C:\\dev_python\\python_study\\python_study_basic_notebook'

# 切换路径

# os.chdir('/Users/david.yi')
# 切换路径大家要参考上面获取的当前路径，根据自己的电脑做适当调整，替换下面 yijeng.zhang  为自己电脑上的用户名
os.chdir('C:\\Users\\yimeng.zhang\\Desktop\\Class')
os.getcwd()

# 返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序。 
# 不包括 '.' 和'..' 即使它在文件夹中。

import os

# os.chdir('C:\\Users\\yimeng.zhang\\Desktop\\Class\\python基础\\python_basic')
os.listdir()

# 注意返回的数据类型是什么，是一个列表

print(type(os.listdir()))

# 计算目录下有多少文件，因为返回结果是 list，因此各类计算都比较方便

a = os.listdir()
print(len(a))

# 可以指定路径参数，来列出该目录下所有文件

# list_a = os.listdir('/Users/david.yi')
list_a = os.listdir('C:\\dev_python\\python_study\\python_study_basic_notebook')

# 可以判断各类情况，比如第一个是 P 字母
for i in list_a:
    if i[0] == 'P':
        print(i)

# 操作系统换行符
# 在一些文本文件处理中有用

os.linesep

# 建立路径

# 切换到当前路径
os.getcwd()
os.mkdir('test')
print('ok')

"""
Explanation: Lesson 7
Python Basic, Lesson 5, v1.0.1, 2016.12 by David.Yi  
Python Basic, Lesson 5, v1.0.2, 2017.03 modified by Yimeng.Zhang 
v1.1, 2020.4 2020.5 edit by David Yi
本次内容要点

文件和目录操作之一：文件和目录操作
文件和目录操作之二：读写文本文件
思考：搜索电脑上指定路径指定类型的文件


文件和目录操作之一
Python 的 os 库有很多和文件、路径和执行系统命令相关的函数。
os 库常用函数

os.sep 可以取代操作系统特定的路径分割符
os.name 字符串指示你正在使用的平台。比如对于Windows，它是'nt'，而对于Linux/Unix用户，它是'posix' 
os.getcwd() 函数得到当前工作目录，即当前Python脚本工作的目录路径
os.chdir(dirname)  改变工作目录到dirname
os.getenv() 用来读取环境变量
os.putenv() 用来设置环境变量 
os.listdir() 返回指定目录下的所有文件名和目录名 
os.remove() 删除一个文件
os.system() 运行shell命令
os.linesep 字符串给出当前平台使用的行终止符。例如，Windows使用'/r/n'，Mac使用'\n'。
os.mkdir() 建立路径
os.rmdir() 删除路径


不同操作系统在路径和文件处理上有一定差异，这里的举例在 Windows 和 macOS 下都测试过

关于文件系统的延展阅读

文件系统介绍 https://zh.wikipedia.org/wiki/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F
windows 文件系统 FAT、FAT32、NTFS 介绍 https://support.microsoft.com/zh-cn/kb/100108
linux 文件系统介绍 http://cn.linux.vbird.org/linux_basic/0230filesystem.php

目前 python 社区逐渐推荐使用pathlib 函数包来进行文件目录相关的访问。和 python 其他一些函数包一样，文件目录操作由于其基本性和发展，造成库比较多，功能有重叠，对于理解python 如何处理文件目录，我们还是沿用了原来的函数包，而 pathlib 是从 python 3.4 版本开始引入并且不断得到完善。之后会有专题来介绍 pathlib。
End of explanation
"""


# 检查给出的路径是否是一个存在的目录，存在

# 确保执行这些测试代码的时候先设定路径到当前 notebook 的路径，或者设定的某个路径
# 进行路径、文件操作时候，还是要谨慎小心一些

os.chdir('C:\\dev_python\\python_study\\python_study_basic_notebook')
s_dir = os.getcwd()
print(s_dir)
print(os.path.isdir(s_dir))
print(os.path.isdir('C:\\Users'))
print(os.path.isdir('C:\\Users222'))

# 检查给出的路径是否是一个存在的目录
# 下面再当前路径下加了个字母，当然是不存在的

os.path.isdir(s_dir + 's')

# 文件不是路径，即便文件存在，也返回 False

os.path.isdir(s_dir + 'test.txt')

# 检查给出的路径是否一个文件，存在
import os
s_dir = os.getcwd()
s_file = os.path.join(s_dir, 'files/test.txt')
print(s_file)
os.path.isfile(s_file)

# 检查给出的路径是否一个文件，不存在

s_dir = os.getcwd()
s_file = os.path.join(s_dir, 'test222.txt')
os.path.isfile(s_file)

# 路径不是文件，所以返回 False

s_dir = os.getcwd()
os.path.isfile(s_dir)

# 对路径和文件都通用的检查方式

s_dir = os.getcwd()
s_file = os.path.join(s_dir, 'test.txt')

print(os.path.exists(s_dir))
print(os.path.exists(s_file))

# 获得路径或者文件的大小

s_dir = os.getcwd()
s_file = os.path.join(s_dir, 'test.txt')

os.path.getsize(s_file)

# 获得路径或者文件的大小

os.path.getsize(s_dir)

# 返回所指向的文件或者目录的最后存取时间
# 返回的时间格式可能和大家想象的不太一样

s_dir = os.getcwd()
s_file = os.path.join(s_dir, 'files/test.txt')

os.path.getatime(s_file)

# 返回所指向的文件或者目录的最后存取时间
import os
import time

# 将日期格式化
dt = time.localtime(os.path.getatime(s_dir))
# print(dt)
print(time.strftime('%Y-%m-%d %H:%M:%S', dt))

# 返回所指向的文件或者目录的最后修改时间

s_file = os.path.join(s_dir, 'files/test.txt')

os.path.getmtime(s_file) 

# 返回所指向的文件或者目录的最后修改时间
# 使用 time.ctime() 方法来格式化日期

import time, os

s_file = os.path.join(s_dir, 'files/test.txt')

time.ctime(os.path.getmtime(s_file))

# 返回规范化的绝对路径
# 会自动补齐完整路径,不管文件是否存在

os.path.abspath('tt1211.txt') 

# 如果输入是绝对路径，返回True

print(os.path.isabs('test.txt'))
print(os.path.isabs('/Users/yijun/test.txt'))

# 返回一个路径的目录名和文件名

# os.chdir('/Users/david.yi/Documents/dev/python_study/python_basic')
# os.chdir('C:\\Users\\yimeng.zhang\\Desktop\\Class\\python基础\\python_basic')
s_dir = os.getcwd()
s_file = os.path.join(s_dir, 'test.txt')
print(s_file)

# 分拆路径和文件名
os.path.split(s_file)

# 返回路径的目录，其实就是 os.path.split(path)的第一个元素

os.path.dirname('/Users/yijun/test.txt')

# 返回路径最后的文件名，其实就是 os.path.split(path)的第二个元素

os.path.basename(s_file)

# 分离文件名与扩展名，返回(fname,fextension)元组 

os.path.splitext(s_file)

# 将多个路径组合后返回，第一个绝对路径之前的参数将被忽略

# os.path.join('/Users/yijun', 'test.txt')
os.path.join('C:\\dev_python\\python_study\\python_study_basic_notebook\\files', 'test.txt')

# 返回list中，所有路径共有的最长的路径

l = ['/Users/yijun/test.txt', '/Users/yijun/test/aaa.txt', '/Users/yijun/bbb.txt']
os.path.commonprefix(l)

# 遍历一个目录下的所有文件

import os 

def list_dir(root_dir): 
    for lists in os.listdir(root_dir): 
        path = os.path.join(root_dir, lists) 
        print(path)
        if os.path.isdir(path): 
            list_dir(path) 

# 注意不要挑选目录下过多文件的，否则会耗费电脑资源
list_dir(os.getcwd())

# 遍历一个目录下的所有文件
# 显示文件的字节数，用 getsize() 

import os 

def list_dir(root_dir): 
    for lists in os.listdir(root_dir): 
        path = os.path.join(root_dir, lists) 
        if lists[0:1] != '.': 
            filesize = os.path.getsize(path)
            print(path, ' ', filesize)
            if os.path.isdir(path): 
                list_dir(path) 

# 注意不要挑选目录下过多文件的，否则会耗费电脑资源
#list_dir('/Users/david.yi/Documents/dev/dig/doc')
list_dir(os.getcwd())

# 遍历一个目录下的所有文件
# 过滤 . 开头的文件，一般是系统文件
# 显示文件的字节数
# 显示指定后缀 ipynb 的文件，引入 endswith 用法

import os 

def list_dir(root_dir): 
    for lists in os.listdir(root_dir): 
        path = os.path.join(root_dir, lists) 
        if lists[0:1] != '.' and lists.endswith('.ipynb'):
            filesize = os.path.getsize(path)
            print(path, ' ', filesize)
            if os.path.isdir(path): 
                list_dir(path) 

# 注意不要挑选目录下过多文件的，否则会耗费电脑资源

# list_dir('/Users/david.yi/Documents/dev/dig/n_query')
list_dir(os.getcwd())

# 写一个可以搜索硬盘上指定路径指定类型的文件
# os.walk() 返回一个三元tuple(root, dirnames, filenames)
# 第一个为起始路径，String
# 第二个为起始路径下的文件夹, List
# 第三个是起始路径下的文件. List

# fnmatch python自带的文件名模式匹配包
# https://docs.python.org/zh-tw/3/library/fnmatch.html
import fnmatch
import os

images = ['*.jpg', '*.jpeg', '*.png', '*.tif', '*.tiff']
matches = []

# for root, dirnames, filenames in os.walk('/Users/david.yi/Documents/dev/'):
for root, dirnames, filenames in os.walk(os.getcwd()):
    for extensions in images:
        for filename in fnmatch.filter(filenames, extensions):
            matches.append(os.path.join(root, filename))

print(matches)

# import os
# for root, dirnames, filenames in os.walk('C:\\Users\\yimeng.zhang\\Desktop\\Class\\python基础\\python_basic'):
#     print(filenames)


"""
Explanation: os.path 常用函数

os.path.isdir() 检查给出的路径是否是一个目录
os.path.isfile() 检查给出的路径是否一个文件
os.path.exists() 检查给出的路径或者文件是否存在
os.path.getsize() 获得路径或者文件的大小
os.path.getatime() 返回所指向的文件或者目录的最后存取时间
os.path.getmtime() 返回所指向的文件或者目录的最后修改时间 
os.path.split() 返回一个路径的目录名和文件名
os.path.abspath() 返回规范化的绝对路径
os.path.isabs() 如果输入是绝对路径，返回True
os.path.split() 将路径分割成目录和文件名的二元素元组
os.path.splitdrive() 返回（drivername，fpath）元组 
os.path.dirname() 返回路径的目录，其实就是 os.path.split(path)的第一个元素
os.path.basename() 返回路径最后的文件名，其实就是 os.path.split(path)的第二个元素
os.path.splitext() 分离文件名与扩展名，返回(fname,fextension)元组 
os.path.join() 将多个路径组合后返回，第一个绝对路径之前的参数将被忽略
os.path.commonprefix(list) 返回list中，所有路径共有的最长的路径
End of explanation
"""


import os

# 获得当前路径
s_dir = os.getcwd()

print(s_dir)

# 拼接完整文件名
filename = os.path.join(s_dir, 'files/test.txt')

print(filename)

# 和读写文件打交道是一件需要小心的事情，这里用了 try-finally 的方式来避免出错
try:
    # 打开文件
    f = open(filename, 'r')
    print(f.read())
finally:
    if f:
        f.close()

# 简化调用方式
# 省却了 try...finally，会有 with 来自动控制保证可以关闭文件等

with open(filename, 'r') as f:
    print(f.read())

# 读入文件所有的内容
# 这样操作对于一般的文件没啥问题，太大的文件不能这样读，内存会不够

with open(filename, 'r') as f:
    lines = f.readlines()

print(type(lines))
print(lines)

# 把读入的文件显示出来

for i in lines:
    print(i)

# 更简单的按行读取文件内容方法

with open(filename, 'r') as f:
    for eachline in f:
        print(eachline)

"""
Explanation: 文件和目录操作之二
读写文件是最常见的IO操作。Python内置了读写文件的函数。
读写文件前，我们先必须了解一下，在磁盘上读写文件的功能都是由操作系统提供的，现代操作系统不允许普通的程序直接操作磁盘，所以，读写文件就是请求操作系统打开一个文件对象，然后，通过操作系统提供的接口从这个文件对象中读取数据，或者把数据写入这个文件对象。
读文件
函数 open() 返回 文件对象，通常的用法需要两个参数：open(filename, mode)。分别是文件名和打开模式
在做下面的例子前，我们要创建一个 test.txt 文件，并且保证其中的内容是如下样式，包含三行内容：

hello
hi
byebye

文件保存在可以访问的目录，我们用到的文件都保存在 notebook 下面的 files 目录；

使用 jupyter 可以直接新建 Text File，来完成建立和编辑文本文件
End of explanation
"""


# 写文件
import os

# 获得当前路径
s_dir = os.getcwd()

# 拼接完整文件名
filename= os.path.join(s_dir, 'files/test2.txt')
print(filename)

# 换行符
br = os.linesep

# 写文件
with open(filename, 'w') as f:
    f.write('Hello, World!' + br)
    f.write('Hello, Shanghai!' + br)
    f.write('Hello, CHINA!' + br)
    f.close()
    
with open(filename, 'r') as f:
    print(f.read())

"""
Explanation: 写文件
写文件和读文件是一样的，唯一区别是调用 open() 函数时，传入标识符 'w' 或者 'wb' 表示写文本文件或写二进制文件。
r 以读方式打开
w 以写方式打开
a 以追加模式打开（必要时候创建新文件）
End of explanation
"""


import pathlib

list(pathlib.Path('.').glob('**/*.ipynb'))


"""
Explanation: 操作系统和文件系统差异处理
如果要写一个 windows 和 macOS 都能用的文件处理软件，很多时候要考虑操作系统带来的差异

linesep 文件中分隔行的字符串；
path.sep 分割文件路径名的字符串；
curdir 当前工作目录的字符串；
pardir 当前工作目录的父目录字符串；


使用 glob 包查找文件
glob 是 python 自己带的一个文件操作相关模块，很简洁，用它可以查找符合自己目的的文件，就类似于 Windows 下的文件搜索，而且也支持通配符: *,?,[] 这三个通配符，* 代表0个或多个字符，? 代表一个字符，[] 匹配指定范围内的字符，如[0-9]匹配数字。
glob 的主要方法也叫 glob，该方法返回所有匹配的文件路径列表，该方法需要一个参数用来指定匹配的路径字符串。

2020.5.10 之前的教程我们推荐试用 glob 函数包来进行查找文件，随着 python 的演进，现在推荐试用 pathlib 函数包来进行文件操作，来获得更加好的兼容性和性能，在pathlib 函数包中同样有 glob 函数，下面简单的演示了试用 pathlib 中的 glob 来遍历搜索文件。
End of explanation
"""


# v1.0.14 edit by Hu Jun, edit by Jia Chunying, #38
# v1.0.17 edit by Hu Jun, #212
# v1.3 edit by David Yi, #272
def find_files(path, exts=None):
    """
    查找路径下的文件，返回指定类型的文件列表

    :param:
        * path: (string) 查找路径
        * exts: (list) 文件类型列表，默认为空

    :return:
        * files_list: (list) 文件列表

    举例如下::

        print('--- find_files demo ---')
        path1 = '/root/fishbase_issue'
        all_files = find_files(path1)
        print(all_files)
        exts_files = find_files(path1, exts=['.png', '.py'])
        print(exts_files)
        print('---')

    执行结果::

        --- find_files demo ---
        ['/root/fishbase_issue/test.png', '/root/fishbase_issue/head.jpg','/root/fishbase_issue/py/man.png'
        ['/root/fishbase_issue/test.png', '/root/fishbase_issue/py/man.png']
        ---

        """
    files_list = []
    for root, dirs, files in os.walk(path):
        for name in files:
            files_list.append(os.path.join(root, name))

    if exts is not None:
        return [file for file in files_list if pathlib.Path(file).suffix in exts]

    return files_list

"""
Explanation: 我们在 fishbase 的 fish_file 包内，也实现了一个搜索文件的功能，也使用了 python 自带的 pathlib 函数包。
End of explanation
"""


