相关文章推荐
骑白马的香菜  ·  Java ...·  2 月前    · 
打篮球的甘蔗  ·  VBA: ...·  1 年前    · 
不开心的烤面包  ·  Make file ...·  1 年前    · 

1. 概述

数据在计算机中有2种存储方式,一种是在内存中,一种是在硬盘中,内存存储运行过程中的数据,如果数据需要掉电或程序退出后仍然能够保存,那么就需要存储到文件中,进行持久化存储。

2. 文件操作流

文件的典型流程为:打开文件->读写文件->关闭文件

# 写文件
f = open(file="demo.txt", mode="w")
f.write("机器未来,追逐未来时代的脉搏")
f.close()

进行写操作后,可以看到目录下多了一个demo.txt文件,打开后可以看到其内容为:机器未来,追逐未来时代的脉搏

# 读文件
f = open(file="demo.txt", mode="r")
print(f.read())
f.close()
机器未来,追逐未来时代的脉搏

3. open函数详解

先来看一下open函数的函数描述

open??
Output exceeds the size limit. Open the full output data in a text editor
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.
[0;31mType:[0m      builtin_function_or_method

可以看到open函数的功能为打开一个文件,返回一个文件流句柄。open的参数较多,平常用的最多的就是3个file、mode、encoding。

3.1 file参数

先来看一下file参数,file参数为将要打开的文件名称,支持相对路径和绝对路径。

3.1.1 相对路径

相对路径是以程序当前运行目录为基准路径向上或向下的路径地址。

在聊相对路径之前,先来看看两个特殊的目录:【.】目录和【..】目录。 在命令行界面下,输入dir -a或ls -la即可看到这两个特殊目录。

zsm@zsm:python14$ ls -la
total 16
drwxrwxrwx 1 zhoushimin zhoushimin     0 Jul  3 21:03 .
drwxrwxrwx 1 zhoushimin zhoushimin 16384 Jul  3 21:00 ..
drwxrwxrwx 1 zhoushimin zhoushimin     0 Jul  3 21:01 a
drwxrwxrwx 1 zhoushimin zhoushimin     0 Jul  3 21:




    
02 b

【.】目录代表当前目录,【..】目录代表父目录或上一级目录,在相对路径的使用中非常好用。

以下面的目录结构为例

├── a │ ├── a1 │ │ ├── app.py │ │ └── test.txt │ └── a2 └── b ├── b1 │ └── b1.txt └── b2

python程序为app.py, 程序的运行目录即为./a/a1/

同级目录文件访问:

它和test.txt在同一个目录,如果要打开test.txt,直接填写test.txt即可,或者加上当前目录【./】也可以,即./test.txt

直接填写文件名

# 在文件a/a1/app.py中写入下列代码
# 读文件
f = open(file="test.txt", mode="r")
print(f.read())
f.close()

执行结果如下:

zsm@zsm:a1$ ls
app.py  test.txt
zsm@zsm:a1$ python app.py 
机器未来,追逐未来时代的脉搏

以【.】目录相对定位

# 在文件a/a1/app.py中写入下列代码
# 读文件
f = open(file="./test.txt", mode="r")
print(f.read())
f.close()

执行结果如下,一模一样:

zsm@zsm:a1$ ls
app.py  test.txt
zsm@zsm:a1$ python app.py 
机器未来,追逐未来时代的脉搏

跨目录访问文件:

如果要访问b1.txt,该如何填写相对路径呢?我们善用【..】访问上级目录。

我们用../../b/b1/b1.txt这个相对路径地址访问b1.txt,第一个../代表回到上级目录a,第二个../代表回到根目录,然后从根目录访问b/b1/b1.txt。我们在b1中写入【这里是b1】

# 读文件
f = open(file="../../b/b1/b1.txt", mode="r")
print(f.read())
f.close()

输出结果:

zsm@zsm:a1$ ls
app.py  test.txt
zsm@zsm:a1$ python app.py 
这里是b1

3.1.2 绝对路径

绝对路径是以系统根目录(linux)或硬盘分区根目录盘符开始的绝对定位路径。

例如test.txt文件的绝对路径如下:

/home/zsm/python14/a/a1/test.txt

我们将绝对路径填充open的file参数,可以获得同样的运行结果。

# 读文件
f = open(file="/home/zsm/python14/a/a1/test.txt", mode="r")
print(f.read())
f.close()

特别注意:绝对路径地址一定要以根目录/开始(linux)或者盘符开始(windows)

3.2 mode参数

模式描述
t文本模式 (默认)。
x写模式,新建一个文件,如果该文件已存在则会报错。
b二进制模式。
+打开一个文件进行更新(可读可写)。
U通用换行模式(不推荐)。
r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+打开一个文件用于读写。文件指针将会放在文件的开头。
rb+以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

mode的参数组合非常多,那么如何快速理解mode的参数呢?

3. open函数详解

3.2 mode参数

模式描述
t文本模式 (默认)。
x写模式,新建一个文件,如果该文件已存在则会报错。
b二进制模式。
+打开一个文件进行更新(可读可写)。
U通用换行模式(不推荐)。
r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
rb以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
r+打开一个文件用于读写。文件指针将会放在文件的开头。
rb+以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
w打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
w+打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
wb+以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
a打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
ab以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
a+打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
ab+以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

mode的参数组合非常多,那么如何快速理解mode的参数呢?

将其分为2类:读写相关和文本类型相关

3.2.1 读写相关

以可读方式打开文件。文件的指针会指向文件的开头,这是默认open文件的mode,若文件不存在,则抛出FileNotFoundError异常

以可写的方式打开文件,若文件存在,则清空之前的内容,从头开始写入;如果文件不存在,则创建文件写入。

以追加的方式写入到文件的末尾。如果文件存在,则从文件的末尾继续写入;如果文件不存在,则创建文件写入。

  • 可读可写+
  • 还有一个特殊的模式+,可以追加在r、w、a后面,赋予可读可写功能,但是对于文件是否存在时的处理仍然遵循r、w、b的逻辑

    3.2.2 文本类型相关

    文件一般分为2类:文本文件和二进制文件。

    文本文件以字符串模式读写。二进制文件以二进制模式读写。

    举个简单的例子,同一个文件用两种不同的模式读写,看下他们的区别。

    # 读文件
    f = open(file="demo.txt", mode="rt")
    print(f.read())
    f.close()
    
    机器未来,追逐未来时代的脉搏
    
    # 读文件
    f = open(file="demo.txt", mode="rb")
    print(f.read())
    f.close()
    
    b'\xe6\x9c\xba\xe5\x99\xa8\xe6\x9c\xaa\xe6\x9d\xa5\xef\xbc\x8c\xe8\xbf\xbd\xe9\x80\x90\xe6\x9c\xaa\xe6\x9d\xa5\xe6\x97\xb6\xe4\xbb\xa3\xe7\x9a\x84\xe8\x84\x89\xe6\x90\x8f'
    

    同一个demo.txt文件,使用两种不同的模式读出来的数据展现方式是不一样的:(1)rt模式读出来的是字符串方式展现的;(2)rb模式读出来的是以二进制方式展示的。

    以文本模式打开文件,这是默认参数

    以二进制模式打开文件,文件中所有的数据,包括字符串结尾的'\0'都被编码为b'\x00'

    综合读写相关和文本类型相关,就形成了模式段首的那么多组合模式。

    3.3 编码方式encoding

    编码的目的是建立语言字符和二进制的映射关系,采用统一的编码规范让信息流通通畅。

    常见的编码方式有ASCII编码、GBK编码、UTF-8编码,不同的编码方式对同一个信息的编码方式是不一样的。更多编码可以阅读www.ruanyifeng.com/blog/2007/1…

    x = "机器未来,追逐未来时代的脉搏"
    # 对文本编码,编码方式为gbk
    x2 = x.encode(encoding="gbk")
    
    b'\xbb\xfa\xc6\xf7\xce\xb4\xc0\xb4\xa3\xac\xd7\xb7\xd6\xf0\xce\xb4\xc0\xb4\xca\xb1\xb4\xfa\xb5\xc4\xc2\xf6\xb2\xab'
    

    可以看到使用gbk编码后,每个汉字被编码为2个字节的数据。

    # 对编码的文本解码,编码方式为gbk
    x3 = x2.decode(encoding="gbk")
    # 可以看到还原为原来的信息了
    
    '机器未来,追逐未来时代的脉搏'
    

    使用同样的编码方式解码后,信息被还原。

    x4 = x2.decode(encoding="utf-8")
    
    ---------------------------------------------------------------------------
    UnicodeDecodeError                        Traceback (most recent call last)
    /media/zhoushimin/Work/220_StudyUpUp/新媒体博客同步空间/BaiduSyncdisk/新媒体/Python快速入门系列/python14-file.ipynb Cell 18' in <cell line: 1>()
    ----> <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000017?line=0'>1</a> x4 = x2.decode(encoding="utf-8")
          <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000017?line=1'>2</a> x4
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb in position 0: invalid start byte
    

    使用不同的编码方式解码,直接报错了。不用的编码方式编码后的数据有信息可以做区分。

    # 写文件
    f = open(file="demo1.txt", mode="w", encoding="utf-8")
    f.write("机器未来,追逐未来时代的脉搏")
    f.close()
    
    # 读文件
    f = open(file="demo1.txt", mode="r", encoding='utf-8')
    print(f.read())
    f.close()
    
    机器未来,追逐未来时代的脉搏
    

    注意:编码方式仅在文本模式时有效,否则会报:ValueError: binary mode doesn't take an encoding argument

    # 使用不同的编码方式打开文件会直接报错。
    f = open(file="demo1.txt", mode="r", encoding='gbk')
    print(f.read())
    f.close()
    
    ---------------------------------------------------------------------------
    UnicodeDecodeError                        Traceback (most recent call last)
    /media/zhoushimin/Work/220_StudyUpUp/新媒体博客同步空间/BaiduSyncdisk/新媒体/Python快速入门系列/python14-file.ipynb Cell 24' in <cell line: 3>()
          <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000023?line=0'>1</a> # 读文件
          <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000023?line=1'>2</a> f = open(file="demo1.txt", mode="r", encoding='gbk')
    ----> <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000023?line=2'>3</a> print(f.read())
          <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000023?line=3'>4</a> f.close()
    UnicodeDecodeError: 'gbk' codec can't decode byte 0xaa in position 8: illegal multibyte sequence
    

    3.4 close关闭文件

    在文章的最开始,我们聊到文件的操作流中,最后一个步骤是关闭文件。打开文件会占用内存空间,关闭文件会释放内存空间,如果因为异常抛出导致文件无法关闭,可能会导致内存被耗尽。那么该怎么做好异常处理呢?

    可以使用异常处理表达式来处理:

    try:
        f = open(file="demo1.txt", mode="r", encoding='gbk')
        print(f.read())
    except Exception as e:  # 未知异常的捕获
        print(f"发生异常, 异常信息:{e}")
    finally:
        f.close()
    

    利用finally的特性(无论是否发生异常,最终都会执行)实现不论是否发生异常都会关闭文件。

    关闭文件,释放内存除了通过close函数之外,还可以通过with上下文表达式来实现。

    with open(file="demo1.txt", mode="r", encoding='gbk') as f:
        print(f.read())
    

    在with上下文表达式中,在表达式内的代码块退出时(不论是否抛出异常),都会自动回收内存。

    注意:如果需要捕获异常,则建议使用try...finally...表达式,如果想简单优雅可以使用with表达式,但是需要手动识别异常处理,with表达式不会抛出异常

    with表达式,是一种常用的文件访问代码样式,使用频次最高。

    4. 读数据相关函数

    4.1 read

    with open(file="demo1.txt", mode="r", encoding='gbk') as f:
        f.read??
    
    Signature: f.read(size=-1, /)
    Docstring:
    Read at most n characters from stream.
    Read from underlying buffer until we have n characters or we hit EOF.
    If n is negative or omitted, read until EOF.
    Type:      builtin_function_or_method
    

    从read函数的描述中可以看到,它有一个参数,可以指定要读取的数据长度,它读到指定长度或到达文件末尾返回。如果指定长度为负数或不填写,则读取整个文件。

    # 读多字节编码文字
    # demo1.txt的内容为:机器未来,追逐未来时代的脉搏
    with open(file="demo1.txt", mode="r", encoding='utf-8') as f:
        print(f.read(size=2))
    
    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    /media/zhoushimin/Work/220_StudyUpUp/新媒体博客同步空间/BaiduSyncdisk/新媒体/Python快速入门系列/python14-file.ipynb Cell 28
    
    
    
    
        
    ' in <cell line: 3>()
          <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000027?line=0'>1</a> # 读多字节编码文字
          <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000027?line=1'>2</a> # demo1.txt的内容为:机器未来,追逐未来时代的脉搏
          <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000027?line=2'>3</a> with open(file="demo1.txt", mode="r", encoding='utf-8') as f:
    ----> <a href='vscode-notebook-cell:/media/zhoushimin/Work/220_StudyUpUp/%E6%96%B0%E5%AA%92%E4%BD%93%E5%8D%9A%E5%AE%A2%E5%90%8C%E6%AD%A5%E7%A9%BA%E9%97%B4/BaiduSyncdisk/%E6%96%B0%E5%AA%92%E4%BD%93/Python%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8%E7%B3%BB%E5%88%97/python14-file.ipynb#ch0000027?line=3'>4</a>     print(f.read(size=2))
    TypeError: read() takes no keyword arguments
    
    # 读单字节编码文字
    # demo2.txt的内容为1234abcd
    with open(file="demo2.txt", mode="r", encoding='utf-8') as f:
        print(f.read(2))
    

    上面2个例子分别展现了读取多字节编码和单字节编码,可以发现个有趣的现象,汉字文件,读取文件为2,我的理解是读取2个字节数据,但是显然不是,它读取了2个汉字出来了,这是为什么呢,它的单位是什么?以文字占用的字节数为单位吗?做一下测试验证一下!

    # demo3.txt的文件内容为:机器未来1234455,汉字和数字混排
    with open(file="demo3.txt", mode="r", encoding='utf-8') as f:
        print(f.read(6))
    
    机器未来12
    

    文件中既有汉字,也有数字,读取长度为6,读取了4个汉字,2个数字,可以说明,在rt模式下读取文件,读取的长度是以文字的个数为单位的,一个汉字占2个字节,那么实际读取长度为2,那么如何按照字节来读取数据呢?测试一下二进制模式读取!

    with open(file="demo3.txt", mode="rb") as f:
        print(f.read(6))
    
    b'\xe6\x9c\xba\xe5\x99\xa8'
    

    可以看到使用rb二进制模式读取时,读取的长度就是6,与读取长度一致。读出来的数据对应【机器未】。

    总结一下:以r模式读取数据时,是以文字(character)的个数为单位的,如果是汉字,那么实际读取2字节,如果是英文字母,那么实际读取1字节;以rb模式读取数据时,指定的长度是多长,读取的数据长度就是多长

    4.2 readline

    一次读取一行数据,并且保留原文本行末换行符

    with open(file="demo1.txt", mode="r", encoding='gbk') as f:
        f.readline??
    
    Signature: f.readline(size=-1, /)
    Docstring:
    Read until newline or EOF.
    Returns an empty string if EOF is hit immediately.
    Type:      builtin_function_or_method
    

    可以看到readline也是支持参数的,默认值为-1,表示读到换行符或文件末尾返回,如果执行大于0的值,则读取对应个数的文字(character)。

    注意:不能使用关键字参数的方式传参,只能使用位置参数的方式传参,因为参数末尾为斜杠,禁止关键字传参,更多函数参数相关请参考博文之前的博文:【【Python零基础入门笔记 | 09】高级程序员绝世心法——模块化之函数封装

    # 按照文字长度读取
    with open(file="demo1.txt", mode="r", encoding='utf-8') as f:
        print(f.readline(4))
    
    # 不传参,读整行
    # demo1.txt的内容为
    # 机器未来,追逐未来时代的脉搏1
    # 机器未来,追逐未来时代的脉搏2
    # 机器未来,追逐未来时代的脉搏3
    # 机器未来,追逐未来时代的脉搏4
    with open(file="demo.txt", mode="r", encoding='utf-8') as f:
        print(f.readline())
    
    机器未来,追逐未来时代的脉搏1
    

    可以看到readline读取了一行数据。

    4.3 readlines

    readlines读取文件所有行并返回列表,列表中的每一个元素就是文件中的每一行数据,每行都会保留末尾的换行符

    # 不传参,读整行
    # demo1.txt的内容为
    # 机器未来,追逐未来时代的脉搏1
    # 机器未来,追逐未来时代的脉搏2
    # 机器未来,追逐未来时代的脉搏3
    # 机器未来,追逐未来时代的脉搏4
    with open(file="demo.txt", mode="r", encoding='utf-8') as f:
        f.readlines??
    
    Signature: f.readlines(hint=-1, /)
    Docstring:
    Return a list of lines from the stream.
    hint can be specified to control the number of lines read: no more
    lines will be read if the total size (in bytes/characters) of all
    lines so far exceeds hint.
    Type:      builtin_function_or_method
    

    readlines也有一个位置参数hint,默认值为-1,表示读取所有行,也可以指定读取hint行,一般我们使用默认参数即可。

    # 不传参,读整行
    # demo1.txt的内容为
    # 机器未来,追逐未来时代的脉搏1
    # 机器未来,追逐未来时代的脉搏2
    # 机器未来,追逐未来时代的脉搏3
    # 机器未来,追逐未来时代的脉搏4
    with open(file="demo.txt", mode="r", encoding='utf-8') as f:
        print(f.readlines())
    
    ['机器未来,追逐未来时代的脉搏1\n', '机器未来,追逐未来时代的脉搏2\n', '机器未来,追逐未来时代的脉搏3\n', '机器未来,追逐未来时代的脉搏4']
    

    5. write写相关函数

    5.1 write

    向文件中写入数据

    with open(file="demo1.txt", mode="w", encoding='utf-8') as f:
        f.write??
    
    Signature: f.write(text, /)
    Docstring:
    Write string to stream.
    Returns the number of characters written (which is always equal to
    the length of the string).
    Type:      builtin_function_or_method
    

    从write函数的描述中可以看到,其有一个位置参数text,看示例:

    # 写入文本数据
    with open(file="demo4.txt", mode="w", encoding='utf-8') as f:
        f.write("机器未来")
    with open(file="demo4.txt", mode="r", encoding='utf-8') as f:
        print(f.readline())
    
    # 写入二进制数据
    with open(file="demo5.txt", mode="wb") as f:
        f.write(b"\x12\x12\x12\x12\x12\x00\x12\x12")
    with open(file="demo5.txt", mode="rb") as f:
        print(f.readline())
    
    b'\x12\x12\x12\x12\x12\x00\x12\x12'
    

    5.3 writelines

    写入多行数据,没有writeline函数。以列表的形式写入到文件,每个元素为一行数据。需要注意的事:如果需要换行,换行符需要手动添加。

    # 写入文本数据
    with open(file="demo5.txt", mode="w", encoding='utf-8') as f:
        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
    
    # 写入文本数据
    with open(file="demo5.txt", mode="w", encoding='utf-8') as f:
        f.writelines(['机器未来,追逐未来时代的脉搏1\n', '机器未来,追逐未来时代的脉搏2\n', '机器未来,追逐未来时代的脉搏3\n', '机器未来,追逐未来时代的脉搏4'])
    with open(file="demo.txt", mode="r", encoding='utf-8') as f:
        print(f.readlines())
    
    ['机器未来,追逐未来时代的脉搏1\n', '机器未来,追逐未来时代的脉搏2\n', '机器未来,追逐未来时代的脉搏3\n', '机器未来,追逐未来时代的脉搏4']
    

    6. 扩展:人工智能用来保存数据最常用的文件接口有哪些?

    最常用不过是joblib和pickle了。

    6.1 pickle

    文件以什么结构写入,就以什么结构读出。

    看下面这个例子,数据结构为字典,写入时直接以字典结构写入,取出时仍然是原来的结构

    import pickle
    data = {"a":2, "b":3, "c":4}
    file = open("data.pkl", "wb")
    pickle.dump(data, file)
    file.close()
    file2 = open("data.pkl", "rb")
    data2 = pickle.load(file2)
    print(data2)
    file2.close()
    

    可以看到例子的使用和普通文件的接口操作大同小异,都是打开文件->读写文件->关闭文件。

    6.2 joblib

    joblib更加简洁,仅需要dump和load接口即可。

    from __future__ import print_function
    from sklearn import svm
    from sklearn import datasets
    from sklearn.externals import joblib
    clf = svm.SVC()
    iris = datasets.load_iris()
    X, y = iris.data, iris.target
    print(X)
    print(y)
    clf.fit(X, y)
    # Save
    joblib.dump(clf, 'save/clf.pkl')
    # restore
    clf3 = joblib.load('save/clf.pkl')
    print(clf3.predict(X[0:1]))
    

    以上就是数据持久化文件相关的学习总结了,下一节讲讲常用的库。

    写在末尾:

  • 博客简介:专注AIoT领域,追逐未来时代的脉搏,记录路途中的技术成长!
  • 专栏简介:本专栏的核心就是:快!快!快!2周快速拿下Python,具备项目开发能力,为机器学习和深度学习做准备。
  • 面向人群:零基础编程爱好者
  • 专栏计划:接下来会逐步发布跨入人工智能的系列博文,敬请期待
  • Python零基础快速入门系列
  • 快速入门Python数据科学系列
  • 人工智能开发环境搭建系列
  • 机器学习系列
  • 物体检测快速入门系列
  • 自动驾驶物体检测系列
  • ......
  • 我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿