2024 Python3.10 系统入门+进阶(十五):文件及目录操作

news2024/9/20 6:10:51

目录

  • 一、文件IO操作
    • 1.1 创建或打开文件
    • 1.2 读取文件
      • 1.2.1 按行读取
      • 1.2.2 多行读取
      • 1.2.3 完整读取
    • 1.3 写入文件
      • 1.3.1 写入字符串
      • 1.3.2 写入序列
    • 1.4 上下文管理
      • 1.4.1 with语句的使用
      • 1.4.2 上下文管理器(拓展----可以学了面向对象之后再回来看)
    • 1.5 文件的遍历
  • 二、os.path模块
  • 三、pathlib模块以及shutil模块
    • 3.1 pathlib模块
    • 3.2 shutil模块
  • 四、csv文件

一、文件IO操作

Python 内置了文件对象,通过 open() 函数可以获取一个文件对象,再通过文件对象的各种方法可以实现对文件的读、写、删除等基本操作。

1.1 创建或打开文件

在全局作用域中,Python3 移除了内置的 file() 函数,把该函数创建文件的功能集成到了 open() 函数中,使用 open() 函数可以打开或创建文件,基本用法如下:

In [1]: open?
Signature:
open(
    file,
    mode='r',
    buffering=-1,
    encoding=None,
    errors=None,
    newline=None,
    closefd=True,
    opener=None,
)
Docstring:
Open file and return a stream.  Raise OSError upon failure.

file is either a text or byte string giving the name (and the path
if the file isn't in the current working directory) of the file to
be opened or an integer file descriptor of the file to be
wrapped. (If a file descriptor is given, it is closed when the
returned I/O object is closed, unless closefd is set to False.)

mode is an optional string that specifies the mode in which the file
is opened. It defaults to 'r' which means open for reading in text
mode.  Other common values are 'w' for writing (truncating the file if
it already exists), 'x' for creating and writing to a new file, and
'a' for appending (which on some Unix systems, means that all writes
append to the end of the file regardless of the current seek position).
In text mode, if encoding is not specified the encoding used is platform
dependent: locale.getpreferredencoding(False) is called to get the
current locale encoding. (For reading and writing raw bytes use binary
mode and leave encoding unspecified.) The available modes are:

========= ===============================================================
Character Meaning
--------- ---------------------------------------------------------------
'r'       open for reading (default)
'w'       open for writing, truncating the file first
'x'       create a new file and open it for writing
'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 newline mode (deprecated)
========= ===============================================================

The default mode is 'rt' (open for reading text). For binary random
access, the mode 'w+b' opens and truncates the file to 0 bytes, while
'r+b' opens the file without truncation. The 'x' mode implies 'w' and
raises an `FileExistsError` if the file already exists.

Python distinguishes between files opened in binary and text modes,
even when the underlying operating system doesn't. Files opened in
binary mode (appending 'b' to the mode argument) return contents as
bytes objects without any decoding. In text mode (the default, or when
't' is appended to the mode argument), the contents of the file are
returned as strings, the bytes having been first decoded using a
platform-dependent encoding or using the specified encoding if given.

'U' mode is deprecated and will raise an exception in future versions
of Python.  It has no effect in Python 3.  Use newline to control
universal newlines mode.

buffering is an optional integer used to set the buffering policy.
Pass 0 to switch buffering off (only allowed in binary mode), 1 to select
line buffering (only usable in text mode), and an integer > 1 to indicate
the size of a fixed-size chunk buffer.  When no buffering argument is
given, the default buffering policy works as follows:

* Binary files are buffered in fixed-size chunks; the size of the buffer
  is chosen using a heuristic trying to determine the underlying device's
  "block size" and falling back on `io.DEFAULT_BUFFER_SIZE`.
  On many systems, the buffer will typically be 4096 or 8192 bytes long.

* "Interactive" text files (files for which isatty() returns True)
  use line buffering.  Other text files use the policy described above
  for binary files.

encoding is the name of the encoding used to decode or encode the
file. This should only be used in text mode. The default encoding is
platform dependent, but any encoding supported by Python can be
passed.  See the codecs module for the list of supported encodings.

errors is an optional string that specifies how encoding errors are to
be handled---this argument should not be used in binary mode. Pass
'strict' to raise a ValueError exception if there is an encoding error
(the default of None has the same effect), or pass 'ignore' to ignore
errors. (Note that ignoring encoding errors can lead to data loss.)
See the documentation for codecs.register or run 'help(codecs.Codec)'
for a list of the permitted encoding error strings.

newline controls how universal newlines works (it only applies to text
mode). It can be None, '', '\n', '\r', and '\r\n'.  It works as
follows:

* On input, if newline is None, universal newlines mode is
  enabled. Lines in the input can end in '\n', '\r', or '\r\n', and
  these are translated into '\n' before being returned to the
  caller. If it is '', universal newline mode is enabled, but line
  endings are returned to the caller untranslated. If it has any of
  the other legal values, input lines are only terminated by the given
  string, and the line ending is returned to the caller untranslated.

* On output, if newline is None, any '\n' characters written are
  translated to the system default line separator, os.linesep. If
  newline is '' or '\n', no translation takes place. If newline is any
  of the other legal values, any '\n' characters written are translated
  to the given string.

If closefd is False, the underlying file descriptor will be kept open
when the file is closed. This does not work when a file name is given
and must be True in that case.

A custom opener can be used by passing a callable as *opener*. The
underlying file descriptor for the file object is then obtained by
calling *opener* with (*file*, *flags*). *opener* must return an open
file descriptor (passing os.open as *opener* results in functionality
similar to passing None).

open() returns a file object whose type depends on the mode, and
through which the standard file operations such as reading and writing
are performed. When open() is used to open a file in a text mode ('w',
'r', 'wt', 'rt', etc.), it returns a TextIOWrapper. When used to open
a file in a binary mode, the returned class varies: in read binary
mode, it returns a BufferedReader; in write binary and append binary
modes, it returns a BufferedWriter, and in read/write mode, it returns
a BufferedRandom.

It is also possible to use a string or bytearray as a file for both
reading and writing. For strings StringIO can be used like a file
opened in a text mode, and for bytes a BytesIO can be used like a file
opened in a binary mode.
Type:      function

open() 函数共包含 8 个参数,比较重要的是前 4 个参数,除了 file 参数外,其他参数都有默认值,可以省略。参数说明如下:

  1. file:必须,指定要打开的文件名称或文件句柄,文件名称包含所在的路径(相对或者绝对路径)
  2. mode:打开模式,即文件打开权限。默认值为 'rt'。文件的打开模式有十几种,简单说明如下所示:
    • 文件格式相关参数:本组参数可以与其他模式参数组合使用,用于指定打开文件的格式,需要根据要打开文件的类型进行选择
      • t 文本模式,默认以文本格式打开文件,一般用于文本文件
      • b 二进制模式,以二进制格式打开文件,一般用于非文本文件,如图片等
    • 通用读写模式相关参数:本组参数可以与文件格式参数组合使用,用于设置基本读、写操作权限,以及文件指针初始位置
      • 'r' 只读模式。默认。以只读方式打开一个文件,文件指针被定位到文件头的位置。如果该文件不存在,则会报错
      • 'w' 只写模式。打开一个文件只用于写入。如果该文件已存在,则打开文件,清空文件内容,并把文件指针定位到文件头位置开始编辑。如果该文件不存在,则创建新文件,打开并编辑
      • 'a' 追加模式。打开一个文件用于追加,仅有只写权限,无权读操作。如果该文件已存在,文件指针被定位到文件尾。新内容被写入到原内容之后。如果该文件不存在,则创建新文件并写入
    • 特殊读写模式相关参数
      • '+' 更新模式。打开一个文件进行更新,具有可读、可写权限。注意,该模式不能单独使用,需要与 r/w/a 模式组合使用。打开文件后,文件指针的位置由 r/w/a 组合模式决定
      • 'x' 只写模式。新建一个文件,打开并写入内容,如果该文件已存在,则会报错
    • 组合模式:文件格式与通用读写模式可以组合使用,另外通过组合+模式可以为只读、只写模式增加写、读的权限
      • 'r+' 文本格式读写。以文本格式打开一个文件用于读、写。文件指针被定位到文件头的位置。新写入的内容将覆盖掉原有文件部分或全部内容;如果该文件不存在,则会报错
      • 'rb' 二进制格式只读。以二进制格式打开一个文件,只能够读取。文件指针被定位到文件头的位置。一般用于非文本文件,如图片等
      • 'rb+' 二进制格式读写。以二进制格式打开一个文件用于读、写。文件指针被定位到文件头的位置。新写入的内容将覆盖掉原有文件部分或全部内容;如果该文件不存在,则会报错。一般用于非文本文件
      • 'w+' 文本格式写读。以文本格式打开一个文件用于写、读。如果该文件已存在,则打开文件,清空原有内容,进入编辑模式。如果该文件不存在,则创建新文件,打开并执行写、读操作
      • 'wb' 二进制格式只写。以二进制格式打开一个文件,只能够写入。如果该文件已存在,则打开文件,清空原有内容,进入编辑模式。如果该文件不存在,则创建新文件,打开并执行只写操作。一般用于非文本文件
      • 'wb+' 二进制格式写读。以二进制格式打开一个文件用于写、读。如果该文件已存在,则打开文件,清空原有内容,进入编辑模式。如果该文件不存在,则创建新文件,打开并执行写、读操作。一般用于非文本文件
      • 'a+' 文本格式读写。以文本格式打开一个文件用于读、写。如果该文件已存在,则打开文件,文件指针被定位到文件尾的位置,新写入的内容添加在原有内容的后面。如果该文件不存在,则创建新文件,打开并执行写、读操作
      • 'ab' 二进制格式只写。以二进制格式打开一个文件用于追加写入。如果该文件已存在,则打开文件,文件指针被定位到文件尾的位置,新写入的内容在原有内容的后面。如果该文件不存在,则创建新文件,打开并执行只写操作
      • 'ab+' 二进制格式读写。以二进制格式打开一个文件用于追加写入。如果该文件已存在,则打开文件,文件指针被定位到文件尾的位置,新写入的内容在原有内容的后面。如果该文件不存在,则创建新文件,打开并执行写、读操作
    • ps: 以二进制模式打开的文件(包含 'b'),返回文件内容为字节对象,而不进行任何解码。在文本模式(包含 't' 时,返回文件内容为字符串,已经解码。
  3. buffering:设置缓冲方式。0表示不缓冲,直接写入磁盘;1表示行缓冲,缓冲区碰到 \n 换行符时写入磁盘;如果为大于1的正整数,则缓冲区文件大小达到该数字大小时,写入磁盘。如果为负值,则缓冲区的缓冲大小为系统默认。
  4. encoding:指定文件的编码方式,默认为 utf-8。该参数只在文本模式下使用。
  5. errors:报错级别。
  6. newline:设置换行符(仅适用于文本模式)。
  7. closefd:布尔值,默认为 True,表示 file 参数为文件名(字符串型);如果为 False,则 file 参数为文件描述符
  8. opener:传递可调用对象

示例1:如果需要创建一个新的文件,在 open() 函数中可以使用 w+ 模式,用 w+ 模式打开文件时,如果该文件不存在,则会创建该文件,而不会抛出异常。

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 8:16
# @Author  : AmoXiang
# @File: open_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

file_name = 'test.txt'  # 创建的文件名
# 建议,使用文件对象时,一定要指定编码,而不是使用默认编码
fp = open(file_name, mode='w+', encoding='utf8')  # 创建文件
print(f'{file_name} 文件创建成功')
fp.close()  # 关闭文件

示例2:r 模式只能打开已存在的文件,当打开不存在的文件时,open() 函数会抛出异常。

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 8:16
# @Author  : AmoXiang
# @File: open_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680


file_name = 'test1.txt'  # 创建的文件名
# 建议,使用文件对象时,一定要指定编码,而不是使用默认编码
fp = open(file_name, mode='r', encoding='utf8')  # 创建文件
'''
FileNotFoundError: [Errno 2] No such file or directory: 'test1.txt'
下面的代码都不会执行,所以文件对象无法关闭,我们可以使用异常进行处理,
关于异常后续文章会进行详细讲解,这里不进行赘述
'''
print(f'{file_name} 文件创建成功')
fp.close()  # 关闭文件

1.2 读取文件

调用 open() 函数后,将会返回一个 file 对象,file 对象包含很多方法,使用这些方法可以对打开的文件进行读写操作。文件的读取有多种方法,可以使用 file 对象的 readline()、readlines() 或 read() 方法读取文件。下面具体介绍这些函数的用法。

1.2.1 按行读取

使用 readline() 方法可以每次读取文件中的一行,包括 "\n" 字符。当文件指针移动到文件的末尾时,如果继续使用 readline() 读取文件,将抛出异常,因此在逐行读取时需要使用条件语句,判断文件指针是否移动到文件的尾部,以便及时中断循环。

【示例1】本示例演示了 readline() 方法的使用。新建文本文件,保存为 test.txt,然后输入下面多行字符串,它们是 file 对象的可用方法。

file.close():	关闭文件。
file.flush():	刷新文件。
file.fileno():	返回文件描述符。
file.isatty():	判断文件是否连接到终端设备。
file.next():	返回下一行。
file.read([size]):	读取指定字节数。
file.readline([size]):	读取整行。
file.readlines([sizeint]):	读取所有行。
file.seek(offset[,whence]):	设置当前位置。
file.tell():	返回当前位置。
file.truncate([size]):	截取文件。
file.write(str):	写入文件。
file.writelines(sequence):	写入序列字符串。

最后,使用下面代码逐行读取 test.txt 文件中的字符串并输出显示,示例代码如下:

In [1]: # -*- coding: utf-8 -*-
   ...: # @Time    : 2024-09-19 8:16
   ...: # @Author  : AmoXiang
   ...: # @File: open_demo.py
   ...: # @Software: PyCharm
   ...: # @Blog: https://blog.csdn.net/xw1680
   ...:
   ...: f = open("test.txt", mode="r", encoding="utf8")  # 打开文本文件
   ...: while True:  # 执行无限循环
   ...:     line = f.readline()  # 读取每行文本
   ...:     if line:  # 如果不是尾行,则显示读取的文本
   ...:         print(line)
   ...:     else:  # 如果是尾行,则跳出循环
   ...:         break
   ...: f.close()  # 关闭文件对象
file.close():  关闭文件。

file.flush():  刷新文件。

file.fileno(): 返回文件描述符。

file.isatty(): 判断文件是否连接到终端设备。

file.next():   返回下一行。

file.read([size]):     读取指定字节数。

file.readline([size]): 读取整行。

file.readlines([sizeint]):     读取所有行。

file.seek(offset[,whence]):    设置当前位置。

file.tell():   返回当前位置。

file.truncate([size]): 截取文件。

file.write(str):       写入文件。

file.writelines(sequence):     写入序列字符串。
Out[1]: <function TextIOWrapper.close()>

readline() 方法包含一个可选参数,设置从文件中读取的字节数。如果把上面示例中第10行代码改为如下语句,读取的方式略有不同,但读取的内容完全相同。该行代码并不表示每行只读取5字节的内容,而是指每行每次读5字节,直到行的末尾。

In [4]: f = open('test.txt', mode='r', encoding='utf8')# 打开文本文件
   ...: while True:     # 执行无限循环
   ...:     line = f.readline(5) # 每次读取每行5个字节
   ...:     if line:    # 如果不是尾行,则显示读取的文本
   ...:         print(line)
   ...:     else:   # 如果是尾行,则跳出循环
   ...:         break
   ...: f.close() # 关闭文件对象
file.
close
():    关
闭文件。

file.
flush
():    刷
新文件。

file.
filen
o():
返回文件描
述符。

file.
isatt
y():
判断文件是
否连接到终
端设备。

file.
next(
):     返回
下一行。

file.
read(
[size
]):    读
取指定字节
数。

file.
readl
ine([
size]
):     读取
整行。

file.
readl
ines(
[size
int])
:      读取所
有行。

file.
seek(
offse
t[,wh
ence]
):     设置
当前位置。


file.
tell(
):     返回
当前位置。


file.
trunc
ate([
size]
):     截取
文件。

file.
write
(str)
:      写入文
件。

file.
write
lines
(sequ
ence)
:      写入序
列字符串。
Out[4]: <function TextIOWrapper.close()>

1.2.2 多行读取

使用 readlines() 方法可以一次性读取文件中的多行数据,然后返回一个列表,用户可以通过循环访问列表中的元素。

【示例 2】示例代码演示了 readlines() 读取文件的方法。

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 8:16
# @Author  : AmoXiang
# @File: open_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

f = open('test.txt', mode='r', encoding='utf8')  # 打开文本文件
lines = f.readlines()  # 读取所有行
for line in lines:
    print(line)  # 从列表中读取每行并显示
f.close()  # 关闭文件对象

在上面的代码中,第9行代码调用了 readlines() 方法,把文件 test.txt 中包含的所有字符串都读取出来;第10行代码循环读取列表 lines 中的内容;第11行代码输出列表 lines 中每个元素的内容,最后手动关闭文件。

1.2.3 完整读取

读取文件最简单的方法是使用 read() 方法,它能够从文件中一次性读出所有内容,并赋值给1个字符串变量。

【示例3】本示例演示了 read() 读取文件的方法。

In [5]: # -*- coding: utf-8 -*-
   ...: # @Time    : 2024-09-19 8:16
   ...: # @Author  : AmoXiang
   ...: # @File: open_demo.py
   ...: # @Software: PyCharm
   ...: # @Blog: https://blog.csdn.net/xw1680
   ...:
   ...: f = open('test.txt', mode='r', encoding='utf8')  # 打开文本文件
   ...: content = f.read()  # 读所有内容
   ...: print(content)  # 显示所有内容
   ...: f.close()  # 关闭文件对象
file.close():  关闭文件。
file.flush():  刷新文件。
file.fileno(): 返回文件描述符。
file.isatty(): 判断文件是否连接到终端设备。
file.next():   返回下一行。
file.read([size]):     读取指定字节数。
file.readline([size]): 读取整行。
file.readlines([sizeint]):     读取所有行。
file.seek(offset[,whence]):    设置当前位置。
file.tell():   返回当前位置。
file.truncate([size]): 截取文件。
file.write(str):       写入文件。
file.writelines(sequence):     写入序列字符串。

在上面的示例代码中,调用 read() 方法把文件 test.txt 中所有的内容存储在变量 content 中,然后输出显示所有文件包含的内容。read() 方法包含一个可选的参数,用来设置返回指定字节的内容。

【示例 4】使用 read() 方法分两次从 test.txt 文件中读取 13 字节和 5 字节内容。

In [6]: # -*- coding: utf-8 -*-
   ...: # @Time    : 2024-09-19 8:16
   ...: # @Author  : AmoXiang
   ...: # @File: open_demo.py
   ...: # @Software: PyCharm
   ...: # @Blog: https://blog.csdn.net/xw1680
   ...:
   ...: f = open('test.txt', mode='r', encoding='utf8')  # 打开文本文件
   ...: str1 = f.read(13)  # 读取14个字节内容
   ...: print(str1)  # 显示内容
   ...: print(f.tell())  # 获取文件对象的当前指针位置
   ...: str1 = f.read(5)  # 读取5个字节内容
   ...: print(str1)  # 显示内容
   ...: print(f.tell())  # 获取文件对象的当前指针位置
   ...: f.close()  # 关闭文件对象
file.close()15
        关闭文件
28

第 1 次调用 f.read(13) 读取文本文件中的 13 个字符,此时当前指针位置下移到第 14 字节位置。第 2 次调用 f.read(5) 读取文本文件中的 5 个字符,此时当前指针位置下移到第 23 字节位置。由于拉丁字符都是单字符字节,所以 1 个字符等于 1 字节,而汉字都是双字节字符,1 个汉字等于 2 字节。file 对象内部将记录文件指针的位置,以便下次操作。只要 file 对象没有执行 close() 方法,文件指针就不会释放,也可以使用 file 对象的 seek() 方法设置当前指针位置。用法如下:

In [8]: f.seek?
Signature: f.seek(cookie, whence=0, /)
Docstring:
Change stream position.

Change the stream position to the given byte offset. The offset is
interpreted relative to the position indicated by whence.  Values
for whence are:

* 0 -- start of stream (the default); offset should be zero or positive
* 1 -- current stream position; offset may be negative
* 2 -- end of stream; offset is usually negative

Return the new absolute position.
Type:      builtin_function_or_method

参数说明: 
1.f 表示文件对象。
2.参数 cookie 表示需要移动偏移的字节数。
3.参数 whence 表示偏移参照点,默认值为0,表示文件的开头;当值为1时,表示当前位置;当值为2时,表示文件的结尾。

【示例 5】使用 read() 方法分两次从 test.txt 文件中读取第1行的 file.close() 和第2行的 file.flush()。

In [9]: # -*- coding: utf-8 -*-
   ...: # @Time    : 2024-09-19 8:16
   ...: # @Author  : AmoXiang
   ...: # @File: open_demo.py
   ...: # @Software: PyCharm
   ...: # @Blog: https://blog.csdn.net/xw1680
   ...:
   ...: f = open('test.txt', mode='rb')  # 使用b模式选项打开文本文件
   ...: str1 = f.read(12)  # 读取12个字节内容
   ...: print(str1)  # 显示内容
   ...: f.seek(15, 1)  # 设置指针以当前位置为参照向后偏移15个字节
   ...: str1 = f.read(12)  # 读取12个字节内容
   ...: print(str1)  # 显示内容
   ...: print(f.tell())  # 获取文件对象的当前指针位置
   ...: f.close()  # 关闭文件对象
b'file.close()'
b'\xb6\xe3\x80\x82\r\nfile.f'
39

1.3 写入文件

使用文件对象的 write() 和 writelines() 方法可以为文件写入内容。

1.3.1 写入字符串

write() 方法能够将传入的字符串写入文件,并返回写入的字符长度。语法格式:

In [10]: f.write?
Docstring:
Write the given buffer to the IO stream.

Returns the number of bytes written, which is always the length of b
in bytes.

Raises BlockingIOError if the buffer is full and the
underlying raw stream cannot accept more data at the moment.
Type:      builtin_function_or_method

【示例 1】使用 open() 函数以 w 模式创建并打开 test1.txt 文件,然后在文件中写入字符串 "Python"

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 8:16
# @Author  : AmoXiang
# @File: open_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

f = open("test1.txt", mode="w", encoding='utf8')  # 打开文件
content = "Python"  # 定义字符串
n = f.write(content)  # 写入字符,
print(n)  # 显示写入字符长度
f.close()  # 关闭文件

上述方法在写入前会清除文件中原有的内容,再重新写入新的内容,相当于 "覆盖" 的方式。如果需要保留文件中原有的内容,只是添加新的内容,可以使用 "a" 模式打开文件。

1.3.2 写入序列

writelines() 方法能够将一个序列的字符串写入文件。语法格式如下:

In [11]: f.writelines?
Signature: f.writelines(lines, /)
Docstring:
Write a list of lines to stream.

Line separators are not added, so it is usual for each of the
lines provided to have a line separator at the end.
Type:      builtin_function_or_method

【示例 2】使用 writelines() 方法把字符串列表写入打开的 test2.txt 文件。

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 8:16
# @Author  : AmoXiang
# @File: open_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

f = open("test2.txt", "w", encoding='utf8')  # 打开文件
w_list = ["Python", "Java", "C"]  # 定义字符串列表
f.writelines(w_list)  # 写入字符串列表
w_list = ["\nPython", "\nJava", "\nC"]  # 定义字符串列表,添加换行符
f.writelines(w_list)  # 写入字符串列表
f.close()  # 关闭文件

writelines() 方法不会换行写入每个元素,如果换行写入每个元素,就需要手动添加换行符 \n 使用 writelines() 方法写入文件的速度更快。如果需要写入文件的字符串非常多,可以使用 writelines() 方法提高效率。如果只需要写入少量的字符串,则直接使用 write() 方法即可。

1.4 上下文管理

如果你有阅读源码的习惯,可能会看到一些优秀的代码经常出现带有 with 关键字的语句,它通常用在什么场景呢?对于系统资源如文件、数据库连接、socket 而言,应用程序打开这些资源并执行完业务逻辑之后,必须做的一件事就是要关闭(断开)该资源。

比如 Python 程序打开一个文件,往文件中写内容,写完之后,就要关闭该文件,否则会出现什么情况呢?极端情况下会出现 Too many open files 的错误,因为系统允许你打开的最大文件数量是有限的。同样,对于数据库,如果连接数过多而没有及时关闭的话,就可能会出现 Can not connect to MySQL server Too many connections,因为数据库连接是一种非常昂贵的资源,不可能无限制的被创建。

1.4.1 with语句的使用

向文件中写入数据的示例代码(基础):

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 10:09
# @Author  : AmoXiang
# @File: with_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

# 1、以写的方式打开文件
f = open("1.txt", "w", encoding="utf8")
# 2、写入文件内容
f.write("hello world")
# 3、关闭文件
f.close()

代码说明如下:文件使用完后必须关闭,因为文件对象会占用操作系统的资源,并且操作系统同一时间能打开的文件数量也是有限的。这种写法可能出现一定的安全隐患,错误代码如下:

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 10:09
# @Author  : AmoXiang
# @File: with_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

# 1、以写的方式打开文件
f = open("1.txt", "r", encoding="utf8")
# 2、写入文件内容
f.write("hello world")
# 3、关闭文件
f.close()

运行结果如下图所示:
在这里插入图片描述
代码说明:由于文件读写时都有可能产生 IOError,一旦出错,后面的 f.close() 就不会调用。为了保证无论是否出错都能正确地关闭文件,我们可以使用 try ... finally 来解决。安全写法, 代码如下:

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 10:09
# @Author  : AmoXiang
# @File: with_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

try:
    # 1、以读的方式打开文件
    f = open("1.txt", "r", encoding='utf8')
    # 2、读取文件内容
    f.write("xxxxx")
except IOError as e:
    print("文件操作出错", e)
finally:
    # 3、关闭文件
    f.close()

运行结果:

文件操作出错 not writable

这种方法虽然代码运行良好,但是缺点就是代码过于冗长,并且需要添加 try-except-finally 语句,不是很方便,也容易忘记。在这种情况下,Python 提供了 with 语句的这种写法,既简单又安全,并且 with 语句执行完成以后自动调用关闭文件操作,即使出现异常也会自动调用关闭文件操作。语法格式:

with 文件对象 as 标识符: # 等同于 标识符 = 文件对象
	pass # 标识符可以在内部使用
说明:
上下文管理
	1.使用with关键字,上下文管理针对的是with后的对象
	2.使用with ... as关键字
	3.上下文管理的语句块并不会开启新的作用域
文件对象上下文管理
	1.进入with时,with后的文件对象是被管理对象
	2.as子句后的标识符,指向with后的文件对象
	3.with语句块执行完的时候,会自动关闭文件对象

with 语句的示例代码:

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 10:09
# @Author  : AmoXiang
# @File: with_demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

filename = './test.txt'
file = open(filename, mode='r', encoding='utf8')
with file as f:
    print(f is file)
    print(1, f.closed)
    print(f.write('abcd'))  # r模式写入失败
print(2, f.closed)  # with中不管是否抛异常,with结束时都会关闭文件对象

1.4.2 上下文管理器(拓展----可以学了面向对象之后再回来看)

一个类只要实现了 __enter__()__exit__() 这个两个方法,通过该类创建的对象我们就称之为上下文管理器对象。上下文管理器可以使用 with 语句,with 语句之所以这么强大,背后是由上下文管理器做支撑的,也就是说刚才使用 open 函数创建的文件对象就是就是一个上下文管理器对象。自定义上下文管理器类,模拟文件操作。定义一个 File 类,实现 __enter__()__exit__() 方法,然后使用 with 语句来完成操作文件, 示例代码:

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 10:20
# @Author  : AmoXiang
# @File: demo.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

class File(object):
    # 初始化方法
    def __init__(self, file_name, mode):
        # 定义变量保存文件名和打开模式
        self.file_name = file_name
        self.mode = mode

    # 上文方法
    def __enter__(self):
        print("进入上文方法")
        # 返回文件资源
        self.f = open(self.file_name, self.mode)
        return self.f

    # 下文方法
    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        with 语句中,即使发生异常信息,也会进入 __exit__ 中
        :param exc_type: 发生异常时,异常的类型
        :param exc_val: 发生异常时,异常的信息
        :param exc_tb: 异常对象,堆栈信息
        :return:如果返回False(代码没有书写返回值默认None,表示为False) 代表
        异常发生以后,异常会继续向外传递。如果返回True,代表异常不再向外传递
        """
        if exc_type:
            print("发生了异常......")
            return True
        print("进入下文方法")
        self.f.close()


if __name__ == '__main__':
    with File("1.txt", "r") as file:
        content = file.read()
        print(content)

运行结果:
在这里插入图片描述
代码说明:

  1. __enter__ 表示上文方法,需要返回一个操作文件对象
  2. __exit__ 表示下文方法,with 语句执行完成会自动执行,即使出现异常也会执行该方法。

上下文管理器的另外一种实现方式: 假如想要让一个函数成为上下文管理器,Python 还提供了一个 @contextmanager 的装饰器,更进一步简化了上下文管理器的实现方式。通过 yield 将函数分割成两部分,yield 上面的语句在 __enter__ 方法中执行,yield 下面的语句在 __exit__ 方法中执行,紧跟在 yield 后面的参数是函数的返回值。示例代码:

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 10:21
# @Author  : AmoXiang
# @File: demo2.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

# 导入装饰器
from contextlib import contextmanager


# 装饰器装饰函数,让其称为一个上下文管理器对象
@contextmanager
def my_open(path, mode):
    try:
        # 打开文件
        file = open(path, mode)
        # yield之前的代码好比是上文方法
        yield file
    except Exception as e:
        print(e)
    finally:
        print("over")
        # yield下面的代码好比是下文方法
        file.close()


# 使用with语句
with my_open('out.txt', 'w') as f:
    f.write("hello , the simplest context manager")

1.5 文件的遍历

类似于日志文件,文件需要遍历,最常用的方式就是逐行遍历。示例:

# -*- coding: utf-8 -*-
# @Time    : 2024-09-19 10:23
# @Author  : AmoXiang
# @File: 文件的遍历.py
# @Software: PyCharm
# @Blog: https://blog.csdn.net/xw1680

filename = './test3.txt'
with open(filename, 'w', encoding='utf8') as f:
    f.write('\n'.join(map(str, range(101, 120))))
with open(filename, mode='r', encoding='utf8') as f:
    for line in f:  # 文件对象是可迭代对象,逐行遍历
        print(line.encode())  # 带换行符

二、os.path模块

参考文章:Python 常用模块(三):os.path模块

三、pathlib模块以及shutil模块

3.1 pathlib模块

3.2 shutil模块

参考文章:Python 常用模块(四):shutil模块

四、csv文件

https://blog.csdn.net/xw1680/article/details/142217826

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2148197.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大语言模型-教育方向数据集

大语言模型-教育方向数据集 编号论文数据集1Bitew S K, Hadifar A, Sterckx L, et al. Learning to Reuse Distractors to Support Multiple-Choice Question Generation in Education[J]. IEEE Transactions on Learning Technologies, 2022, 17: 375-390.Televic, NL, https…

79页 PPT华为项目管理经典培训教材(高级)

读者朋友大家好&#xff0c;最近有会员朋友咨询晓雯&#xff0c;需要《79页PPT华为项目管理经典培训教材》资料&#xff0c;欢迎大家文末扫码下载学习。 一、华为项目管理理念方法 &#xff08;一&#xff09;项目管理基本概念与方法 项目启动 明确项目目标&#xff1a;华为…

SAP B1 流程实操 - 营销单据销售部分(上)

背景 在 SAP B1 中&#xff0c;最重要的模块就是【销售】&#xff0c;企业可能不涉及生产和库存&#xff08;贸易公司&#xff09;&#xff0c;甚至不涉及采购&#xff08;服务业&#xff09;&#xff0c;但是一定会有基本的 销售。本文中我们讲解 销售 模块的基本核心&#x…

【QT】基于HTTP协议的网络应用程序

目录 1 HTTP概述 2 QT中实现高层网络操作的类 3 使用HTTP类请求数据 4 基于HTTP协议的网络文件下载 1 HTTP概述 HTTP&#xff08;超文本传输协议&#xff09;是互联网上应用最为广泛的协议之一&#xff0c;它定义了客户端和服务器之间进行通信的规则。HTTP是一种无状态的协议…

rcc 不是内部或外部命令,也不是可运行的程序或批处理文件

D:\Windows Kits\10\bin\10.0.22621.0\x86 将上述路径添加到环境变量中&#xff0c;重启电脑

【微服务-注册中心】

注册中心的作用&#xff1a; 微服务将业务拆分成了一个一个服务&#xff0c;当实现一个业务的时需要调用多个服务&#xff0c;那么每个服务的调用都需要知道它的URL。如何更方便的调用&#xff0c;注册中心就出现了。 我们可以把注册中心当作通讯录&#xff0c;通讯录中记录了服…

【JS】postMessage与MessageChannel

前言 postMessage 和 MessageChannel 都是用来实现跨文档、跨窗口或跨线程&#xff08;Web Worker&#xff09;的消息传递机制。 postMessage 可以在 iframe、同源或跨源窗口之间传递数据&#xff0c;也可以用于主线程与 Web Worker 之间的通信。 postMessage 是一种单向的…

Django 聚合查询

文章目录 一、聚合查询二、使用步骤1.准备工作2.具体使用3.分组查询&#xff08;annotate&#xff09;1.定义2.使用3.具体案例 4.F() 查询1.定义2.使用 5.Q() 查询1.定义2.查询 一、聚合查询 使用聚合查询前要先从 django.db.models 引入 Avg、Max、Min、Count、Sum&#xff0…

VS code EXPLORER 中不显示指定文件及文件夹设置(如.pyc, __pycache__, .vscode 文件)

VS code EXPLORER 中不显示指定文件及文件夹设置 引言正文方法1打开方式1打开方式2 方法2 引言 VS code 号称地表最强轻量级编译器&#xff0c;其最大的优势在于用户可以根据自己的需求下载适合自己的 extension。从而定制个性化的编译器。然而&#xff0c;本人今天遇到了一个…

如何调用API接口:一份简明指南

在软件开发中&#xff0c;调用API接口是一项基本而重要的技能。API&#xff08;应用程序编程接口&#xff09;允许不同程序之间进行交互&#xff0c;使得数据和功能可以跨应用程序共享。本文将为你提供一份简明的指南&#xff0c;帮助你理解如何调用API接口。 什么是API接口&am…

Android中的引用类型:Weak Reference, Soft Reference, Phantom Reference 和 WeakHashMap

在Android开发中&#xff0c;内存管理是一个非常重要的话题。为了更好地管理内存&#xff0c;Java和Android提供了多种引用类型&#xff0c;包括Weak Reference、Soft Reference、Phantom Reference以及WeakHashMap。这些引用类型在不同的场景下可以帮助我们更有效地管理内存&a…

(笔记)mac笔记本调节键盘速率

我在使用neovim的时候&#xff0c;发现按下hjkl或者shift[]来进行移动的时候 开始延迟大概几百毫秒的时间才开始移动 所以我上网找了下方法 发现修改这了可以改变速率 我就直接拉到了fast 芜湖 起飞 local opt vim.opt local o vim.o local g vim.go.timeoutlen 100 o…

论文速递!时序预测!DCSDNet:双卷积季节性分解网络,应用于天然气消费预测过程

本期推文将介绍一种新的时序预测方法:双卷积季节性分解网络&#xff08;Dual Convolution withSeasonal Decomposition Network, DCSDNet&#xff09;在天然气消费预测的应用&#xff0c;这项研究发表于《Applied Energy》期刊。 针对天然气消费的多重季节性和非规律性&#x…

汽车焊机数据通信:Profinet转Canopen网关的神奇连接

在汽车制造领域&#xff0c;汽车焊机的高效、稳定运行对于整车质量至关重要。而Profinet转Canopen网关在汽车焊机的数据通信中发挥着关键作用。 Profinet是一种广泛应用于工业自动化领域的通信协议&#xff0c;具有高速、实时、可靠等特点。Canopen则在汽车电子等领域有着广泛…

软件渗透测试流程有哪些?专业软件测评公司简析渗透测试的好处

软件渗透测试是进行软件安全测评的重要环节&#xff0c;旨在通过模拟攻击手段发现软件系统的脆弱性。这种安全测试方法能够帮助开发人员和系统管理员发现并修复潜在的安全漏洞&#xff0c;以确保软件系统的安全性和完整性。软件渗透测试是一项高度技术性的任务&#xff0c;需要…

口哨声、歌声、boing声和biotwang声:用AI识别鲸鱼叫声

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

算法打卡 Day41(动态规划)-理论基础 + 斐波那契数 + 爬楼梯 + 使用最小花费爬楼梯

文章目录 理论基础Leetcode 509-斐波那契数题目描述解题思路 Leetcode 70-爬楼梯题目描述解题思路 Leetcode 746-用最小花费爬楼梯题目描述解题思路 理论基础 动态规划&#xff0c;简称 DP&#xff0c;其中的每一个状态一定是由上一个状态推导出来的&#xff0c;而贪心算法没有…

Mastering Qt 番外 —— 添加源码调试

笔者最近正在尝试深入的学习Qt框架&#xff0c;经常需要明确我经常使用的类底下发生了什么&#xff0c;因此笔者决定仔细研究一下如何进行源码级别的调试 此篇文章将会介绍如何使用Qt Creator这个IDE进行调试。最终效果如下 EasyWay 笔者采用的是这个最简单明了的方式&#xff…

回归预测|基于鹈鹕优化径向基神经网络的数据回归预测Matlab程序POA-RBF 多特征输入单输出 含基础RBF

回归预测|基于鹈鹕优化径向基神经网络的数据回归预测Matlab程序POA-RBF 多特征输入单输出 含基础RBF 文章目录 一、基本原理1. **饥饿游戏搜索优化算法&#xff08;POA&#xff09;简介**2. **径向基神经网络&#xff08;RBF&#xff09;简介**3. **POA-RBF回归预测流程**1. **…

重修设计模式-设计原则

重修设计模式-设计原则 设计原则 设计原则是软件编码时所遵循的规则&#xff0c;旨在帮助开发者创建出既满足功能需求又易于维护、可扩展且美观的设计&#xff0c;理解设计原则可以提升代码质量、减少错误以及促进团队协作&#xff0c;但对设计原则的理解要灵活&#xff0c;不…