云计算、AI、云原生、大数据等一站式技术学习平台

网站首页 > 教程文章 正文

python散装笔记——30: 文件与文件夹的输入或输出

jxf315 2025-01-21 18:44:38 教程文章 21 ℃


Parameter

Details

filename

文件的路径,或者,如果文件在工作目录中,文件的文件名

access_mode

决定文件打开方式的字符串值

buffering

一个整数值,用于可选的行缓冲

在存储、读取或交流数据时,使用 Python 处理操作系统的文件既必要又简单。不像其他语言,文件的输入和输出需要复杂的读写对象,Python 简化了这一过程,只需要命令来打开、读/写和关闭文件。本主题将解释 Python 如何与操作系统上的文件进行交互。

1: 文件模式

您可以使用不同的模式打开文件,这些模式由模式参数指定。这些模式包括

  • 'r' - 读取模式。默认模式。它只允许读取文件,不允许修改文件。使用该模式时,文件必须存在。
  • 'w' - 写入模式。如果文件不存在,它将创建一个新文件,否则将擦除文件并允许你写入。
  • 'a' - 追加模式。它会将数据写入文件末尾。这种模式不会擦除文件,而且文件必须存在。
  • 'rb' - 二进制读取模式。这与 r 相似,只是读数会强制为二进制模式。这也是默认选择。
  • 'r+' - 同时使用读取模式和写入模式。这样就可以同时读取和写入文件,而无需使用 rw
  • 'rb+' - 二进制读写模式。与 r+ 相同,只是数据是二进制的
  • 'wb' - 二进制写入模式。与 w 相同,只是数据是二进制的。
  • 'w+' - 读写模式。与 r+ 完全相同,但如果文件不存在,则会创建一个新文件。否则,文件将被覆盖。
  • 'wb+' - 二进制模式下的写入和读取模式。与 w+ 相同,但数据为二进制。
  • 'ab' - 以二进制模式追加。除了数据是二进制的,其他与 a 相似。
  • 'a+' - 追加和读取模式。与 w+ 类似,如果文件不存在,它将创建一个新文件。否则,如果文件存在,文件指针将位于文件末尾。
  • 'ab+' - 二进制追加和读取模式。与 a+ 相同,只是数据是二进制的。
with open(filename, 'r') as f:
  f.read()
with open(filename, 'w') as f:
  f.write(filedata)
with open(filename, 'a') as f:
  f.write('\\n' + newdata)


r

r+

w

w+

a

a+

读取

写入

创建文件

擦除文件

初始位置

开头

开头

开头

开头

末尾

末尾

Python 3 增加了一种新的独占创建模式,这样就不会意外截断或覆盖现有文件。

  • 'x' - 打开用于独占创建,如果文件已经存在,将引发 FileExistsError
  • 'xb' -以二进制形式打开,用于独占创建写入模式。与 x 相同,只是数据是二进制的。
  • 'x+' - 读写模式。与 w+ 类似,如果文件不存在,它将创建一个新文件。否则将引发 FileExistsError
  • 'xb+' - 写入和读取模式。与 x+ 完全相同,但数据是二进制的


x

x+

读取

写入

创建文件

擦除文件

初始位置

开头

开头

建议用更 Pythonic 的风格编写文件打开代码:

try:
  with open("fname", "r") as fout:
    # Work with your open file
except FileExistsError:
  # Your error handling goes here

2: 逐行的方式读取一个文件

有一个文件 myfile.txt,里面有两行文字:第一行为 hello ;第二行为 world

最简单的逐行遍历文件的方法:

with open('myfile.txt', 'r') as fp:
  for line in fp:
    print(line)

readline() 允许对逐行迭代进行更精细的控制。下面的示例等同于上面的示例:

with open('myfile.txt', 'r') as fp:
  while True:
    cur_line = fp.readline()
    # If the result is an empty string
    if cur_line == '':
      # We have reached the end of the file
      break
    print(cur_line)

同时使用 for 循环迭代器和 readline() 被认为是不好的做法。

更常见的做法是使用 readlines() 方法来存储文件行数的可迭代集合:

with open("myfile.txt", "r") as fp:
  lines = fp.readlines()
for i, line in zip(range(len(lines)),lines):
  print("Line " + str(i) + ": " + line)

这将打印出以下内容:

Line 0: hello

Line 1: world

3: 遍历文件(递归)

要遍历包括子目录在内的所有文件,请使用 os.walk

import os
for root, folders, files in os.walk(root_dir):
  for filename in files:
    print root, filename

root_dir 可以是“.”,表示从当前目录启动,也可以是任何其他路径。

如果还想获取文件的信息,可以使用更有效的 os.scandir 方法,如下所示:

for entry in os.scandir(path):
  if not entry.name.startswith('.') and entry.is_file():
    print(entry.name)

4: 获取一个文件的全部内容

文件 i/o 的首选方法是使用 with 关键字。这将确保文件句柄在读写完成后关闭。

with open('myfile.txt') as in_file:
  content = in_file.read()
  
print(content)

或者,如果要手动关闭文件,也可以不调用,直接调用 close

in_file = open('myfile.txt', 'r')
content = in_file.read()
print(content)
in_file.close()

请注意,如果不使用 with 语句,可能会意外地保持文件打开状态,以防出现类似下面代码中的意外异常:

in_file = open('myfile.txt', 'r')
raise Exception("oops")
in_file.close() # 永远不会被调用

5: 将数据写入文件

with open('myfile.txt', 'w') as f:
  f.write("Line 1")
  f.write("Line 2")
  f.write("Line 3")
  f.write("Line 4")

打开 myfile.txt,可以看到其内容如下,上面咱们演示的 helloworld 两行内容被覆盖为新的内容:

Line 1Line 2Line 3Line 4


Python 不会自动添加换行符,需要手动添加:

with open('myfile.txt', 'w') as f:
  f.write("Line 1\n")
  f.write("Line 2\n")
  f.write("Line 3\n")
  f.write("Line 4\n")

Line 1

Line 2

Line 3

Line 4


在写入以文本模式打开的文件(默认)时,不要使用 os.linesep 作为行结束符;而应使用 \n

如果要指定编码,只需在 open 函数中添加编码参数即可:

with open('my_file.txt', 'w', encoding='utf-8') as f:
  f.write('utf-8 text')

也可以使用 print 语句写入文件。Python 2 与 Python 3 的机制不同,但概念是一样的,都是将输出到屏幕,然后发送到文件。

with open('fred.txt', 'w') as outfile:
  s = "I'm Not Dead Yet!"
  print(s) # 写入到标准输出
  print(s, file = outfile) # 写入到打开的输出文件
  
  # 注意:可以直接或通过变量确保文件最终值为 None 从而指定文件参数并写入屏幕
  myfile = None
  print(s, file = myfile) # 写入到标准输出
  print(s, file = None) # 写入到标准输出

与使用写入功能不同,打印功能会自动添加换行符。

6: 检查文件或路径是否存在

采用 EAFP 编码方式并尝试打开它。

import errno
try:
  with open(path) as f:
    # File exists
except IOError as e:
  # Raise the exception if it is not ENOENT (No such file or directory)
  if e.errno != errno.ENOENT:
    raise
  # No such file or directory

这样做还可以避免在检查和使用文件之间被其他进程删除文件时出现竞赛条件。在以下情况下可能会出现这种竞赛条件:

  • 使用 os 模块:
import os
os.path.isfile('/path/to/some/file.txt')
  • 使用 pathlib 模块:
import pathlib
path = pathlib.Path('/path/to/some/file.txt')
if path.is_file():
  ...

要检查给定路径是否存在,可以按照上述 EAFP 程序进行,也可以明确检查路径:

import os
path = "/home/myFiles/directory1"

if os.path.exists(path):
  ## Do stuff

7: 使用 mmap 进行随机文件访问

通过使用 mmap 模块,用户可以将文件映射到内存中,从而随机访问文件中的位置。这是使用普通文件操作的一种替代方法。

import mmap

with open('myfile.txt', 'r+') as fd:
  # 0:映射整个文件
  mm = mmap.mmap(fd.fileno(), 0)
  
  # 打印位于索引 5 到 10 的字符
  print(mm[5:10])
  
  # 印从 mm 当前位置开始的一行
  print(mm.readline())
  
  # 在第 5 个索引中写入字符
  mm[5] = 'a'
  
  # 将 mm 的位置返回到文件的开头
  mm.seek(0)
  
  # 关闭 mmap 对象
  mm.close()

8: 替换文件中的文本

import fileinput

replacements = {'Search1': 'Replace1', 'Search2': 'Replace2'}

for line in fileinput.input('filename.txt', inplace=True):
  for search_for in replacements:
    replace_with = replacements[search_for]
    line = line.replace(search_for, replace_with)
  print(line, end='')

9: 检查文件是否为空

>>> import os
>>> os.stat(path_to_file).st_size == 0

或者

>>> import os
>>> os.path.getsize(path_to_file) > 0

不过,如果文件不存在,两者都会抛出异常。为了避免捕捉这样的错误,可以这样做:

import os
def is_empty_file(fpath):
  return os.path.isfile(fpath) and os.path.getsize(fpath) > 0

将返回一个 bool 值。

10: 读取一定范围行数之间的文件数据

因此,假设您只想遍历文件中的某些特定行

为此,您可以使用 itertools 工具

import itertools

with open('myfile.txt', 'r') as f:
  for line in itertools.islice(f, 12, 30):
    # do something here

这将读取第 13 行至第 20 行,因为在 python 中,索引从 0 开始,所以第 1 行的索引为 0。

还可以通过使用next()关键字读取一些额外的行。

在使用文件对象作为可迭代对象时,请不要在此处使用 readline() 语句,因为这两种遍历文件的技术不能混用

11: 复制目录树

import shutil
source='//<NasIP>/Daily Reports'
destination='D:\\Reports\\Today'
shutil.copytree(source, destination)

目标目录必须不存在。

12: 将一个文件的内容复制到另一个文件中

with open(input_file, 'r') as in_file, open(output_file, 'w') as out_file:
  for line in in_file:
    out_file.write(line)

使用 shutil 模块:

import shutil
shutil.copyfile(src, dst)

Tags:

最近发表
标签列表