Python 有很多内置的模块和函数可用于文件的操作处理,这些函数都分布在几个模块上:如 通过本教程,你可以:
Python 读写数据到文件使用 Python 读取和写入文件数据非常简单。 为此,我们必须首先以适当的模式打开文件。 以下是如何打开文本文件并读取其内容的示例: with open('data.txt', 'r') as f: data = f.read()
with open('data.txt', 'w') as f: data = 'some data to be written to the file' f.write(data) 在上面的示例中, 获取目录列表假设您当前的工作目录有一个名为 my_directory 的子目录,其中包含以下内容: .├── file1.py├── file2.csv├── file3.txt├── sub_dir│ ├── bar.py│ └── foo.py├── sub_dir_b│ └── file4.txt└── sub_dir_c ├── config.py └── file5.txt 内置的 在传统 Python 版本中获取目录列表在 Python 3 之前的 Python 版本中, >>> import os>>> entries = os.listdir('my_directory/')
>>> os.listdir('my_directory/')['sub_dir_c', 'file1.py', 'sub_dir_b', 'file3.txt', 'file2.csv', 'sub_dir'] 像这样列出的目录列表不容易阅读。使用循环打印出对 >>> entries = os.listdir('my_directory/')>>> for entry in entries:... print(entry)......sub_dir_cfile1.pysub_dir_bfile3.txtfile2.csvsub_dir 在现代 Python 版本中的获取目录列表在现代版本的 Python 中,
>>> import os>>> entries = os.scandir('my_directory/')>>> entries<posix.ScandirIterator object at 0x7f5b047f3690>
import oswith os.scandir('my_directory/') as entries: for entry in entries: print(entry.name) 在这里, sub_dir_cfile1.pysub_dir_bfile3.txtfile2.csvsub_dir 获取目录列表的另一种方法是使用 from pathlib import Pathentries = Path('my_directory/')for entry in entries.iterdir(): print(entry.name)
在上面的示例中,我们调用
运行上面的代码会产生以下结果: sub_dir_cfile1.pysub_dir_bfile3.txtfile2.csvsub_dir 使用 以下是目录列表功能: 这些函数返回了一个包含了目录中所有内容的列表,包括子目录。这些操作可能并不总是您想要的。下一节我们将介绍如何从目录列表中进行结果过滤。 列出目录中的所有文件本节将向您展示如何使用 import os# List all files in a directory using os.listdirbasepath = 'my_directory/'for entry in os.listdir(basepath): if os.path.isfile(os.path.join(basepath, entry)): print(entry) 在这里,对 file1.pyfile3.txtfile2.csv 列出目录中文件的一个更简单方法是使用 import os# List all files in a directory using scandir()basepath = 'my_directory/'with os.scandir(basepath) as entries: for entry in entries: if entry.is_file(): print(entry.name) 使用 file1.pyfile3.txtfile2.csv 以下是使用 from pathlib import Pathbasepath = Path('my_directory/')files_in_basepath = basepath.iterdir()for item in files_in_basepath: if item.is_file(): print(item.name) 在这里,我们在 file1.pyfile3.txtfile2.csv 如果将 for 循环和 if 语句组合成单个生成器表达式,则上面的代码可以更简洁。 Dan Bader 有一篇关于生成器表达式(generator expressions)和列表推导(list comprehensions)的优秀文章,感兴趣的可以去看一下。 上面的代码,经修改后的版本如下所示: from pathlib import Path# List all files in directory using pathlibbasepath = Path('my_directory/')files_in_basepath = (entry for entry in basepath.iterdir() if entry.is_file())for item in files_in_basepath: print(item.name) 这将产生与之前的示例完全相同的输出。本节展示了使用 列出子目录要列出子目录而不是文件,请使用以下方法之一。 如何使用 import os# List all subdirectories using os.listdirbasepath = 'my_directory/'for entry in os.listdir(basepath): if os.path.isdir(os.path.join(basepath, entry)): print(entry) 当您多次调用 sub_dir_csub_dir_bsub_dir 如何使用 import os# List all subdirectories using scandir()basepath = 'my_directory/'with os.scandir(basepath) as entries: for entry in entries: if entry.is_dir(): print(entry.name) 与文件列表示例中一样,此处在 sub_dir_csub_dir_bsub_dir 如何使用 from pathlib import Path# List all subdirectory using pathlibbasepath = Path('my_directory/')for entry in basepath.iterdir(): if entry.is_dir(): print(entry.name) 本示例在 basepath 迭代器的每个条目上调用 sub_dir_csub_dir_bsub_dir 获取文件属性Python 可以轻松检索文件大小和修改时间等文件属性。这是通过
下面的示例显示了如何获取 my_directory 中文件的上次修改时间。输出以秒为单位: >>> import os>>> with os.scandir('my_directory/') as dir_contents:... for entry in dir_contents:... info = entry.stat()... print(info.st_mtime)...1539032199.00520351539032469.63244751538998552.24029231540233322.40093161537192240.04973391540266380.3434134
>>> from pathlib import Path>>> current_dir = Path('my_directory')>>> for path in current_dir.iterdir():... info = path.stat()... print(info.st_mtime)...1539032199.00520351539032469.63244751538998552.24029231540233322.40093161537192240.04973391540266380.3434134 在上面的示例中,代码循环遍历 from datetime import datetimefrom os import scandirdef convert_date(timestamp): d = datetime.utcfromtimestamp(timestamp) formated_date = d.strftime('%d %b %Y') return formated_datedef get_files(): dir_entries = scandir('my_directory/') for entry in dir_entries: if entry.is_file(): info = entry.stat() print(f'{entry.name}\t Last Modified: {convert_date(info.st_mtime)}') 这将首先获取 my_directory 中的文件列表及其属性,然后调用 传递给
这些指令整合到一起产生如下所示的输出: >>> get_files()file1.py Last modified: 04 Oct 2018file3.txt Last modified: 17 Sep 2018file2.txt Last modified: 17 Sep 2018 将日期和时间转换为字符串的语法可能非常混乱。要了解更多信息,请查看相关的官方文档。或者参考另一个更易于记忆的方法:http:///。 创建目录我们编写的程序需要创建目录以便在其中存储数据时,可以参考 创建单个目录要创建单个目录,请将目录路径作为参数传递给 import osos.mkdir('example_directory/') 如果目录已存在, from pathlib import Pathp = Path('example_directory/')p.mkdir() 如果路径已经存在, >>> p.mkdir()Traceback (most recent call last): File '<stdin>', line 1, in <module> File '/usr/lib/python3.5/pathlib.py', line 1214, in mkdir self._accessor.mkdir(self, mode) File '/usr/lib/python3.5/pathlib.py', line 371, in wrapped return strfunc(str(pathobj), *args)FileExistsError: [Errno 17] File exists: '.'[Errno 17] File exists: '.' 为了避免这样的错误,可以在错误发生时捕获错误并让用户知道: from pathlin Pathp = Path('example_directory')try: p.mkdir()except FileExistsError as exc: print(exc) 或者,我们也可以通过将 from pathlib import Pathp = Path('example_directory')p.mkdir(exist_ok=True) 这样一来,如果目录已存在,则不会引发错误。 创建多个目录
import osos.makedirs('2018/10/05') 这将创建一个包含文件夹 2018,10 和 05 的嵌套目录结构: .└── 2018 └── 10 └── 05
import osos.makedirs('2018/10/05', mode=0o770) 这将创建 2018/10/05 目录结构,并为所有者和组用户提供读、写和执行权限。默认模式为 执行 $ tree -p -i ..[drwxrwx---] 2018[drwxrwx---] 10[drwxrwx---] 05 这将打印出当前目录的目录树。 如我们所见,所有目录都拥有 import pathlibp = pathlib.Path('2018/10/05')p.mkdir(parents=True) 将 默认情况下,如果目标目录已存在, 运行上面的代码会产生一个像下面一样的目录结构: .└── 2018 └── 10 └── 05 我更喜欢在创建目录时使用 文件名模式匹配使用上述方法之一获取目录中的文件列表后,您很可能希望搜索与特定模式匹配的文件。 这些是可以使用的方法和功能:
本节中的示例将在名为 some_directory 的目录上执行,该目录具有以下结构: .├── admin.py├── data_01_backup.txt├── data_01.txt├── data_02_backup.txt├── data_02.txt├── data_03_backup.txt├── data_03.txt├── sub_dir│ ├── file1.py│ └── file2.py└── tests.py1 directory, 10 files 如果您正在使用 Bash shell,则可以使用以下命令创建上述目录结构: $ mkdir some_directory$ cd some_directory/$ mkdir sub_dir$ touch sub_dir/file1.py sub_dir/file2.py$ touch data_{01..03}.txt data_{01..03}_backup.txt admin.py tests.py 这将创建 some_directory/ 目录,进入该目录,然后创建 sub_dir。第 4 行是在 sub_dir 中创建 file1.py 和 file2.py,最后一行使用扩展创建所有其他文件。 要了解有关 shell 扩展的更多信息,请访问此站点。 使用字符串方法Python 有几种用于修改和操作字符串的内置方法。当您在文件名中使用搜索模式时,其中两个方法 >>> import os>>> # Get .txt files>>> for f_name in os.listdir('some_directory'):... if f_name.endswith('.txt'):... print(f_name) 上面的代码找到 data_01.txtdata_03.txtdata_03_backup.txtdata_02_backup.txtdata_02.txtdata_01_backup.txt 使用 fnmatch 进行简单文件名模式匹配字符串方法的匹配能力有限。但 >>> import os>>> import fnmatch>>> for file_name in os.listdir('some_directory/'):... if fnmatch.fnmatch(file_name, '*.txt'):... print(file_name) 这将迭代 更高级的模式匹配假设我们要查找符合特定条件的 >>> for filename in os.listdir('.'):... if fnmatch.fnmatch(filename, 'data_*_backup.txt'):... print(filename) 在此处,仅打印与数据 data_03_backup.txtdata_02_backup.txtdata_01_backup.txt 使用 glob 的文件名模式匹配模式匹配的另一个有用模块是
UNIX 和相关的系统使用 ? 和 * 通配符来把名称模式转化成文件列表。这称为通配。 例如,在 UNIX shell 中键入 这是一个如何使用 >>> import glob>>> glob.glob('*.py')['admin.py', 'tests.py']
>>> import glob>>> for name in glob.glob('*[0-9]*.txt'):... print(name) 这将查找文件名中包含数字的所有文本(.txt)文件: data_01.txtdata_03.txtdata_03_backup.txtdata_02_backup.txtdata_02.txtdata_01_backup.txt
>>> import glob>>> for file in glob.iglob('**/*.py', recursive=True):... print(file) 此示例使用 运行上面的程序会产生以下结果: admin.pytests.pysub_dir/file1.pysub_dir/file2.py
>>> from pathlib import Path>>> p = Path('.')>>> for name in p.glob('*.p*'):... print(name)admin.pyscraper.pydocs.pdf 调用
回顾一下,这是我们在本节中介绍的功能表: 遍历目录和文件遍历目录树并处理树中的文件是最常见的编程任务之一。 让我们来探索如何使用内置的 Python 函数 .|├── folder_1/| ├── file1.py| ├── file2.py| └── file3.py|├── folder_2/| ├── file4.py| ├── file5.py| └── file6.py|├── test1.txt└── test2.txt 以下是一个示例,演示如何使用
# Walking a directory tree and printing the names of the directories and filesfor dirpath, dirnames, files in os.walk('.'): print(f'Found directory: {dirpath}') for file_name in files: print(file_name)
在每次迭代时,它会打印出它找到的子目录和文件的名称: Found directory: .test1.txttest2.txtFound directory: ./folder_1file1.pyfile3.pyfile2.pyFound directory: ./folder_2file4.pyfile5.pyfile6.py 要以自下而上的方式遍历目录树,需要将 for dirpath, dirnames, files in os.walk('.', topdown=False): print(f'Found directory: {dirpath}') for file_name in files: print(file_name) 传递 Found directory: ./folder_1file1.pyfile3.pyfile2.pyFound directory: ./folder_2file4.pyfile5.pyfile6.pyFound directory: .test1.txttest2.txt 如我们所见,程序通过在列出根目录的内容之前列出子目录的内容来启动。 这在我们想要递归删除文件和目录的情况下非常有用(我们将在下面章节部分中学习如何执行此操作)。默认情况下, 创建临时文件和目录Python 提供了一个名为
以下是创建临时文件的方法: from tempfile import TemporaryFile# Create a temporary file and write some data to itfp = TemporaryFile('w+t')fp.write('Hello universe!')# Go back to the beginning and read data from filefp.seek(0)data = fp.read()# Close the file, after which it will be removedfp.close() 第一步是从 在上面的示例中,模式为'w + t',这使得 写入文件后,我们可以从中读取并在完成处理后将其关闭。文件关闭后,将从文件系统中删除。如果需要命名使用 使用tempfile创建的临时文件和目录存储在一个特殊的用于存储临时文件的系统目录中。 Python 通过搜索标准目录列表以找到用户可以在其中创建文件的目录。 在 Windows 上,目录按顺序为
with TemporaryFile('w+t') as fp: fp.write('Hello universe!') fp.seek(0) fp.read()# File is now closed and removed 这将创建一个临时文件并从中读取数据。 一旦读取文件的内容,就会关闭临时文件并从文件系统中删除。
>>> import tempfile>>> with tempfile.TemporaryDirectory() as tmpdir:... print('Created temporary directory ', tmpdir)... os.path.exists(tmpdir)...Created temporary directory /tmp/tmpoxbkrm6cTrue>>> # Directory contents have been removed...>>> tmpdir'/tmp/tmpoxbkrm6c'>>> os.path.exists(tmpdir)False 调用 在上下文管理器退出上下文后,临时目录将被删除,并且对 删除文件和目录我们可以使用 在 Python 中删除文件要删除单个文件,请使用
import osdata_file = 'C:\\Users\\vuyisile\\Desktop\\Test\\data.txt'os.remove(data_file) 使用 import osdata_file = 'C:\\Users\\vuyisile\\Desktop\\Test\\data.txt'os.unlink(data_file) 在文件上调用 import osdata_file = 'home/data.txt'# If the file exists, delete itif os.path.isfile(data_file): os.remove(data_file)else: print(f'Error: {data_file} not a valid filename')
以下示例说明如何在删除文件时使用异常处理来处理错误: import osdata_file = 'home/data.txt'# Use exception handlingtry: os.remove(data_file)except OSError as e: print(f'Error: {data_file} : {e.strerror}') 上面的代码尝试在检查其类型之前先删除该文件。如果 最后,我们还可以使用 from pathlib import Pathdata_file = Path('home/data.txt')try: data_file.unlink()except IsADirectoryError as e: print(f'Error: {data_file} : {e.strerror}') 上面的代码将创建一个名为 删除目录Python 的标准库提供以下删除目录的功能:
要删除单个目录或文件夹,请使用 import ostrash_dir = 'my_documents/bad_dir'try: os.rmdir(trash_dir)except OSError as e: print(f'Error: {trash_dir} : {e.strerror}') 这里,通过将其路径作为参数传递给 Traceback (most recent call last): File '<stdin>', line 1, in <module>OSError: [Errno 39] Directory not empty: 'my_documents/bad_dir' 或者,我们可以使用 from pathlib import Pathtrash_dir = Path('my_documents/bad_dir')try: trash_dir.rmdir()except OSError as e: print(f'Error: {trash_dir} : {e.strerror}') 在这里,我们创建一个指向要删除的目录的 Path 对象。如果目录为空,则在 Path 对象上调用 删除整个目录树要删除非空目录和整个目录树,Python 提供了 import shutiltrash_dir = 'my_documents/bad_dir'try: shutil.rmtree(trash_dir)except OSError as e: print(f'Error: {trash_dir} : {e.strerror}') 当对 import osfor dirpath, dirnames, files in os.walk('.', topdown=False): try: os.rmdir(dirpath) except OSError as ex: pass 这将遍历目录树并尝试删除它找到的每个目录。如果目录不为空,则引发 下表列出了本节中涉及的功能: 文件和目录复制,移动及重命名Python 附带的 Python 中的文件复制
import shutilsrc = 'path/to/file.txt'dst = 'path/to/dest_dir'shutil.copy(src, dst)
要在复制时保留所有文件元数据,请使用 import shutilsrc = 'path/to/file.txt'dst = 'path/to/dest_dir'shutil.copy2(src, dst) 使用 Python 中的目录复制虽然 以下是如何将一个文件夹的内容复制到其他位置的示例: >>> import shutil>>> shutil.copytree('data_1', 'data1_backup')'data1_backup' 在此示例中, 移动文件和目录要将文件或目录移动到其他位置,请使用 >>> import shutil>>> shutil.move('dir_1/', 'backup/')'backup' 如果 重命名文件和目录Python 内置的 >>> os.rename('first.zip', 'first_01.zip') 上面的代码行将 重命名文件或目录的另一种方法是使用 >>> from pathlib import Path>>> data_file = Path('data_01.txt')>>> data_file.rename('data.txt') 要使用 归档归档是将多个文件打包成一个文件的便捷方式。两种最常见的存档类型是 ZIP 和 TAR。我们编写的 Python 程序可以从归档中创建,读取和提取数据。我们将在本节中学习如何从两种存档格式文件中读取和写入数据。 读取 ZIP 文件
import zipfilewith zipfile.ZipFile('data.zip', 'r') as zipobj: 在这里,您创建一个 ZipFile 对象,传入 ZIP 的文件名称并在读取模式下打开。打开 ZIP 文件后,可以通过 .|├── sub_dir/| ├── bar.py| └── foo.py|├── file1.py├── file2.py└── file3.py 要获取存档中的文件列表,请在 ZipFile 对象上调用 import zipfilewith zipfile.ZipFile('data.zip', 'r') as zipobj: zipobj.namelist() 以上代码将会产生一个列表结果: ['file1.py', 'file2.py', 'file3.py', 'sub_dir/', 'sub_dir/bar.py', 'sub_dir/foo.py']
import zipfilewith zipfile.ZipFile('data.zip', 'r') as zipobj: bar_info = zipobj.getinfo('sub_dir/bar.py') bar_info.file_size 代码结果如下: 15277
以下示例说明如何在 Python REPL 中检索有关已归档文件的更多详细信息。假设已导入 >>> bar_info.date_time(2018, 10, 7, 23, 30, 10)>>> bar_info.compress_size2856>>> bar_info.filename'sub_dir/bar.py'
提取 ZIP 归档
默认情况下,这些方法将文件解压缩到当前目录。 它们都采用可选的路径参数,允许我们指定要将文件提取到的其他目录。 如果该目录不存在,则会自动创建该目录。 要从存档中提取文件,请执行以下操作: >>> import zipfile>>> import os>>> os.listdir('.')['data.zip']>>> data_zip = zipfile.ZipFile('data.zip', 'r')>>> # Extract a single file to current directory>>> data_zip.extract('file1.py')'/home/terra/test/dir1/zip_extract/file1.py'>>> os.listdir('.')['file1.py', 'data.zip']>>> # Extract all files into a different directory>>> data_zip.extractall(path='extract_dir/')>>> os.listdir('.')['file1.py', 'extract_dir', 'data.zip']>>> os.listdir('extract_dir')['file1.py', 'file3.py', 'file2.py', 'sub_dir']>>> data_zip.close() 第三行代码是对 接下来,在读取模式下打开 下一行代码打印一个目录列表,显示当前目录除原始存档之外的解压缩文件。之后的行显示了如何将整个存档解压缩到 从受密码保护的归档中提取数据
>>> import zipfile>>> with zipfile.ZipFile('secret.zip', 'r') as pwd_zip:... # Extract from a password protected archive... pwd_zip.extractall(path='extract_dir', pwd='Quish3@o') 这将以读取模式打开 secret.zip 存档。接下来,把密码提供给 创建新的 ZIP 存档要创建新的 ZIP 存档,请以写入模式(w)打开 >>> import zipfile>>> file_list = ['file1.py', 'sub_dir/', 'sub_dir/bar.py', 'sub_dir/foo.py']>>> with zipfile.ZipFile('new.zip', 'w') as new_zip:... for name in file_list:... new_zip.write(name) 在该示例中,我们以写入模式打开 要将文件添加到现有存档,请以追加模式打开 >>> # Open a ZipFile object in append mode>>> with zipfile.ZipFile('new.zip', 'a') as new_zip:... new_zip.write('data.txt')... new_zip.write('latin.txt') 在这里,我们打开在上一个示例中以追加模式创建的 new.zip 存档。在追加模式下打开 打开 TAR 归档TAR 文件是 ZIP 等未压缩文件的存档。它们可以使 用 gzip,bzip2 和 lzma 压缩方法进行压缩。 这样做是为了从存档中读取: import tarfilewith tarfile.open('example.tar', 'r') as tar_file: print(tar_file.getnames())
使用 "r","w" 或 "a" 模式分别打开未压缩的 TAR 文件以进行读取,写入和追加。要打开压缩的 TAR 文件,需要将模式参数传递给
>>> import tarfile>>> tar = tarfile.open('example.tar', mode='r')>>> tar.getnames()['CONTRIBUTING.rst', 'README.md', 'app.py'] 这将返回一个包含存档内容名称的列表。 可以使用特殊属性访问存档中每个条目的元数据: >>> for entry in tar.getmembers():... print(entry.name)... print(' Modified:', time.ctime(entry.mtime))... print(' Size :', entry.size, 'bytes')... print()CONTRIBUTING.rst Modified: Sat Nov 1 09:09:51 2018 Size : 402 bytesREADME.md Modified: Sat Nov 3 07:29:40 2018 Size : 5426 bytesapp.py Modified: Sat Nov 3 07:29:13 2018 Size : 6218 bytes 在此示例中,循环遍历 从 TAR 存档中提取文件在本节中,我们学习一下如何使用下面的方法从 TAR 存档中提取文件:
要从 TAR 存档中提取单个文件,可以使用 >>> tar.extract('README.md')>>> os.listdir('.')['README.md', 'example.tar']
>>> tar.extractall(path="extracted/")
$ lsexample.tar extracted README.md$ tree.├── example.tar├── extracted| ├── app.py| ├── CONTRIBUTING.rst| └── README.md└── README.md1 directory, 5 files$ ls extracted/app.py CONTRIBUTING.rst README.md 要提取文件对象以进行读取或写入,可以使用 >>> f = tar.extractfile('app.py')>>> f.read()>>> tar.close() 打开的存档文件应在读取或写入后始终关闭。要关闭存档,需要在存档文件句柄上调用 创建新的 TAR 存档创建新的 TAR 存档,可以参考下面的做法: >>> import tarfile>>> file_list = ['app.py', 'config.py', 'CONTRIBUTORS.md', 'tests.py']>>> with tarfile.open('packages.tar', mode='w') as tar:... for file in file_list:... tar.add(file)>>> # Read the contents of the newly created archive>>> with tarfile.open('package.tar', mode='r') as t:... for member in t.getmembers():... print(member.name)app.pyconfig.pyCONTRIBUTORS.mdtests.py 首先,我们要创建要添加到存档的文件列表,这样就不必手动添加每个文件。 下一行代码使用了 创建并填充存档后, 要将新文件添加到现有存档,可以以追加模式('a')打开存档: >>> with tarfile.open('package.tar', mode='a') as tar:... tar.add('foo.bar')>>> with tarfile.open('package.tar', mode='r') as tar:... for member in tar.getmembers():... print(member.name)app.pyconfig.pyCONTRIBUTORS.mdtests.pyfoo.bar 在追加模式('a')下打开存档允许我们向其添加新文件而不删除其中已存在的文件。 处理压缩归档
例如,要读取或写入使用 gzip 压缩的 TAR 存档数据,请分别使用 'r:gz' 或 'w:gz' 模式: >>> files = ['app.py', 'config.py', 'tests.py']>>> with tarfile.open('packages.tar.gz', mode='w:gz') as tar:... tar.add('app.py')... tar.add('config.py')... tar.add('tests.py')>>> with tarfile.open('packages.tar.gz', mode='r:gz') as t:... for member in t.getmembers():... print(member.name)app.pyconfig.pytests.py 'w:gz' 可以以 gzip 压缩写入的方式打开压缩的存档文件,'r:gz' 模式则可以以 gzip 压缩读取的方式打开压缩的存档文件。需要注意的是,我们无法在追加模式下打开压缩的存档。要将文件添加到压缩存档,我们必须创建新存档。 创建归档更简单的方法Python 标准库还支持使用 使用 |
|
来自: 文炳春秋 > 《Python资料》