Python 文件 IO 和 Python 工具详解

在本章中,我们将详细讨论文件 I/O,即文件的读取、写入和附加。我们还将讨论 Python 工具,这些工具支持操作文件和与操作系统交互。每个主题都有不同程度的复杂性,我们将通过一个例子来讨论。让我们开始吧!

我们讨论文件 I/O 有两个原因:

因此,我们认为将 Python 中的文件 I/O 作为自己的一章来讨论会很有用(详细文档可从这里获得:https://docs.python.org/3/tutorial/inputoutput.html#reading-和编写文件,并讨论在 Raspberry Pi Zero 上开发应用程序时它可以发挥作用的示例。

让我们创建一个简单的文本文件,read_file.txt包含以下文本:I am learning Python Programming using the Raspberry Pi Zero并将其保存到 code samples 目录(或您选择的任何位置)。

要读取文件,我们需要使用 Python 的内置函数:open打开文件。让我们快速查看代码片段,演示如何打开一个文本文件来读取它的内容并将其打印到屏幕上:

if __name__ == "__main__":
    # open text file to read
    file = open('read_line.txt', 'r')
    # read from file and store it to data
    data = file.read()
    print(data)
    file.close()

让我们详细讨论此代码段:

  1. 读取文本文件内容的第一步是使用内置功能open打开文件。所讨论的文件需要作为参数传递,并带有一个标志r,表明我们正在打开文件以读取内容(在讨论每个读/写文件时,我们将讨论其他标志选项)
  2. 打开文件后,open函数返回存储在file变量中的指针(指向文件对象的地址)。
       file = open('read_line.txt', 'r')
  1. 此文件指针用于读取文件内容并将其打印到屏幕上:
       data = file.read() 
       print(data)
  1. 读取文件内容后,调用close()函数关闭文件。

使用 IDLE3 或命令行终端运行前面的代码片段(可与本章一起下载-read_from_file.py。文本文件的内容将按如下方式打印到屏幕上:

    I am learning Python Programming using the Raspberry Pi Zero

有时,有必要逐行读取文件的内容。在 Python 中,有两个选项可以执行此操作:readline()readlines()

  • readline():顾名思义,这个内置功能可以一次读取一行。让我们用一个例子来回顾一下:
       if __name__ == "__main__": 
          # open text file to read
          file = open('read_line.txt', 'r') 

          # read a line from the file
          data = file.readline() 
          print(data) 

          # read another line from the file 
          data = file.readline() 
          print(data) 

          file.close()

当执行前面的代码段时(可随本章下载为read_line_from_file.py,打开read_line.txt文件,readline()函数返回一行。此行存储在变量数据中。由于该函数在该程序中调用了两次,因此输出如下:

 I am learning Python Programming using the Raspberry Pi Zero. 

 This is the second line.

每次调用readline函数时都会返回一个新行,当到达文件末尾时,它会返回一个空字符串。

  • readlines():此函数以行形式读取文件的全部内容,并将每个内容存储到列表中:
       if __name__ == "__main__": 
           # open text file to read
           file = open('read_lines.txt', 'r') 

           # read a line from the file
           data = file.readlines() 
           for line in data: 
               print(line) 

           file.close()

由于文件的行存储为列表,因此可以通过迭代列表来检索:

       data = file.readlines() 
           for line in data: 
               print(line)

前面的代码片段可作为read_lines_from_file.py与本章一起下载。

执行以下步骤以写入文件:

  1. 写入文件的第一步是打开具有写入标志的文件:w。如果作为参数传递的文件名不存在,将创建一个新文件:
      file = open('write_file.txt', 'w')
  1. 打开文件后,下一步是将要写入的字符串作为参数传递给write()函数:
      file.write('I am excited to learn Python using
      Raspberry Pi Zero')
  1. 让我们将代码放在一起,将字符串写入文本文件,关闭它,重新打开文件,并将文件内容打印到屏幕上:
       if __name__ == "__main__": 
          # open text file to write
          file = open('write_file.txt', 'w') 
          # write a line from the file
          file.write('I am excited to learn Python using
          Raspberry Pi Zero \n') 
          file.close() 

          file = open('write_file.txt', 'r') 
          data = file.read() 
          print(data) 
          file.close()
  1. 上述代码片段可与本章一起下载(write_to_file.py
  2. 执行前面的代码段时,输出如下所示:
       I am excited to learn Python using Raspberry Pi Zero

每当使用写入标志w打开文件时,文件内容将被删除并重新打开以写入数据。有一个备用标志a可以将数据追加到文件的末尾。如果文件(作为要打开的参数传递)不存在,此标志还会创建一个新文件。让我们考虑下面的代码片段,在这里我们将一行添加到文本文件 OutT2^。

if __name__ == "__main__": 
   # open text file to append
   file = open('write_file.txt', 'a') 
   # append a line from the file
   file.write('This is a line appended to the file\n') 
   file.close() 

   file = open('write_file.txt', 'r') 
   data = file.read() 
   print(data) 
   file.close()

当执行前面的代码片段时(可与本章一起下载-append_to_file.py,字符串This is a line appended to the file被追加到文件文本的末尾。该文件的内容将包括以下内容:

    I am excited to learn Python using Raspberry Pi Zero
 This is a line appended to the file

打开文件后,文件 I/O 中使用的文件指针将从文件的开头移动到结尾。可以将指针移动到特定位置并从该位置读取数据。当我们对文件的特定行感兴趣时,这一点特别有用。让我们从前面的例子中考虑文本文件。该文件的内容包括:

    I am excited to learn Python using Raspberry Pi Zero
 This is a line appended to the file

让我们尝试跳过第一行,使用seek只读取第二行:

if __name__ == "__main__": 
   # open text file to read

   file = open('write_file.txt', 'r') 

   # read the second line from the file
   file.seek(53) 

   data = file.read() 
   print(data) 
   file.close()

在前面的示例中(与本章一起作为seek_in_file.py下载),seek函数用于将指针移动到第一行末尾的字节53。然后读取文件内容并将其存储到变量中。执行此代码段时,输出如下所示:

    This is a line appended to the file

因此,seek 允许将文件指针移动到特定位置。

seek功能允许将指针移动到特定位置,并从该位置读取一个字节或n字节。让我们重温阅读write_file.txt并尝试阅读句子I am excited to learn Python using Raspberry Pi Zero中的excited一词。

if __name__ == "__main__": 
   # open text file to read and write 
   file = open('write_file.txt', 'r') 

   # set the pointer to the desired position 
   file.seek(5) 
   data = file.read(1) 
   print(data) 

   # rewind the pointer
   file.seek(5) 
   data = file.read(7) 
   print(data) 
   file.close()

上述代码可通过以下步骤进行解释:

  1. 在第一步中,使用read标志打开文件,并将文件指针设置为第五个字节(使用seek)——文本文件内容中字母e的位置。
  2. 现在,我们从文件中读取一个字节,将其作为参数传递给read函数。当整数作为参数传递时,read函数返回文件中相应的字节数。当没有传递任何参数时,它将读取整个文件。如果文件为空,read函数返回空字符串:
       file.seek(5) 
       data = file.read(1) 
       print(data)
  1. 在第二部分中,我们尝试从文本文件中读取单词excited。我们将指针的位置倒回第五个字节。然后我们从文件中读取七个字节(单词excited的长度)。
  2. 执行代码段时(可随本章下载为seek_to_read.py,程序应打印字母e和单词excited
       file.seek(5) 
       data = file.read(7) 
       print(data)

我们讨论了使用rw标志读取和写入文件。还有一个叫r+。此标志允许读取和写入文件。让我们回顾一个使我们能够理解此标志的示例。

让我们再次回顾一下write_file.txt的内容:

    I am excited to learn Python using Raspberry Pi Zero
 This is a line appended to the file

我们将第二行修改为:This is a line that was modified。代码示例可与本章一起下载为seek_to_write.py

if __name__ == "__main__": 
   # open text file to read and write 
   file = open('write_file.txt', 'r+') 

   # set the pointer to the desired position 
   file.seek(68) 
   file.write('that was modified \n') 

   # rewind the pointer to the beginning of the file
   file.seek(0) 
   data = file.read() 
   print(data) 
   file.close()

让我们回顾一下此示例的工作原理:

  1. 本例中的第一步是使用r+标志打开文件。这样可以读取和写入文件。
  2. 下一步是移动到文件的第 68 个字节
  3. that was modified字符串在该位置写入文件。字符串末尾的空格用于覆盖第二个句子的原始内容。
  4. 现在,文件指针设置为文件的开头,并读取其内容。
  5. 执行上述代码段时,修改后的文件内容将按如下方式打印到屏幕上:
       I am excited to learn Python using Raspberry Pi Zero
 This is a line that was modified

还有另一个a+标志,允许将数据追加到文件末尾并同时读取。我们将让读者使用到目前为止讨论的示例来解决这个问题。

We have discussed different examples on reading and writing to files in Python. It can be overwhelming without sufficient experience in programming. We strongly recommend working through the different code samples provided in this chapter

使用a+标志打开write_file.txt文件(在不同示例中讨论),并在文件中添加一行。使用seek设置文件指针并打印其内容。您只能在程序中打开该文件一次。

到目前为止,我们讨论了可用于以不同模式打开文件的不同标志。我们讨论的示例遵循一种常见模式:打开文件、执行读/写操作和关闭文件。使用with关键字与文件交互是一种优雅的方式。 如果在与文件交互的代码块执行过程中出现任何错误,with关键字确保在退出代码块时关闭文件并清理相关资源。一如既往,让我们用一个例子来回顾一下with关键字:

if __name__ == "__main__": 
   with open('write_file.txt', 'r+') as file: 
         # read the contents of the file and print to the screen 
         print(file.read()) 
         file.write("This is a line appended to the file") 

         #rewind the file and read its contents 
         file.seek(0) 
         print(file.read()) 
   # the file is automatically closed at this point 
   print("Exited the with keyword code block")

在前面的示例(with_keyword_example中,我们跳过了关闭文件,因为一旦缩进代码块的执行完成,with关键字负责关闭文件。with关键字还负责关闭文件,同时由于错误而离开代码块。这可确保在任何情况下都能正确清理资源。接下来,我们将在文件 I/O 中使用with关键字。

让我们讨论一下 Python 编程的一些方面,这些方面在使用 Raspberry Pi 开发应用程序时特别有用。Python 中提供的configparser就是这样一个工具。configparser模块(https://docs.python.org/3.4/library/configparser.html 用于读取/写入应用程序的配置文件。

在软件开发中,配置文件通常用于在 Raspberry Pi 的上下文中存储常量,如访问凭证、设备 ID 等,configparser可用于存储所有正在使用的 GPIO 引脚列表、通过 I2C 接口连接的传感器地址等。让我们讨论三个我们学习使用configparser模块的例子。在第一个示例中,我们将使用configparser创建一个config文件。

在第二个示例中,我们将使用configparser读取配置值,在第三个示例中,我们将在最后一个示例中讨论修改配置文件。

例 1

在第一个示例中,让我们创建一个配置文件,该文件存储的信息包括设备 ID、正在使用的 GPIO 引脚、传感器接口地址、调试开关和访问凭据:

import configparser 

if __name__ == "__main__": 
   # initialize ConfigParser 
   config_parser = configparser.ConfigParser() 

   # Let's create a config file 
   with open('raspi.cfg', 'w') as config_file: 
         #Let's add a section called ApplicationInfo 
         config_parser.add_section('AppInfo') 

         #let's add config information under this section 
         config_parser.set('AppInfo', 'id', '123') 
         config_parser.set('AppInfo', 'gpio', '2') 
         config_parser.set('AppInfo', 'debug_switch', 'True') 
         config_parser.set('AppInfo', 'sensor_address', '0x62') 

         #Let's add another section for credentials 
         config_parser.add_section('Credentials') 
         config_parser.set('Credentials', 'token', 'abcxyz123') 
         config_parser.write(config_file) 
   print("Config File Creation Complete")

让我们详细讨论前面的代码示例(可与本章一起下载为config_parser_write.py

  1. 第一步是导入configparser模块并创建ConfigParser类的实例。此实例将被称为config_parser
       config_parser = configparser.ConfigParser()
  1. 现在,我们使用with关键字打开一个名为raspi.cfg的配置文件。由于该文件不存在,因此将创建一个新的配置文件。

  2. 配置文件将由两部分组成,即AppInfoCredentials

  3. 这两个部分可以使用add_section方法创建,如下所示:

       config_parser.add_section('AppInfo') 
       config_parser.add_section('Credentials')
  1. 每个部分将由一组不同的常数组成。可以使用set方法将每个常数添加到相关部分。set方法所需的参数包括节名(参数/常量将位于节名下)、参数/常量的名称及其对应的值。例如:id参数可以添加到AppInfo部分,并指定一个值123,如下所示:
       config_parser.set('AppInfo', 'id', '123')
  1. 最后一步是将这些配置值保存到文件中。这是通过config_parser方法write实现的。一旦程序在with关键字下退出缩进块,文件即关闭:
       config_parser.write(config_file)

We strongly recommend trying the code snippets yourself and use these snippets as a reference. You will learn a lot by making mistakes and possibly arrive with a better solution than the one discussed here.

当执行前面的代码段时,将创建一个名为raspi.cfg的配置文件。配置文件的内容将包括如下所示的内容:

[AppInfo] 
id = 123 
gpio = 2 
debug_switch = True 
sensor_address = 0x62 

[Credentials] 
token = abcxyz123

例 2

让我们讨论一个示例,其中我们从上一个示例中创建的配置文件中读取配置参数:

import configparser 

if __name__ == "__main__": 
   # initialize ConfigParser 
   config_parser = configparser.ConfigParser() 

   # Let's read the config file 
   config_parser.read('raspi.cfg') 

   # Read config variables 
   device_id = config_parser.get('AppInfo', 'id') 
   debug_switch = config_parser.get('AppInfo', 'debug_switch') 
   sensor_address = config_parser.get('AppInfo', 'sensor_address') 

   # execute the code if the debug switch is true 
   if debug_switch == "True":
         print("The device id is " + device_id) 
         print("The sensor_address is " + sensor_address)

If the config files are created in the format shown, the ConfigParser class should be able to parse it. It is not really necessary to create config files using a Python program. We just wanted to show programmatic creation of config files as it is easier to programmatically create config files for multiple devices at the same time.

上述示例可与本章一起下载(config_parser_read.py。让我们讨论一下这个代码示例是如何工作的:

  1. 第一步是初始化名为config_parserConfigParser类的实例。
  2. 第二步是使用实例方法read加载和读取配置文件。
  3. 因为我们知道配置文件的结构,所以让我们继续阅读AppInfo部分下的一些常量。可使用get方法读取配置文件参数。必需的参数包括 config 参数所在的部分和参数的名称。例如:配置id参数位于AppInfo部分下。因此,该方法所需的参数包括AppInfoid
      device_id = config_parser.get('AppInfo', 'id')
  1. 既然配置参数已读入变量,那么让我们在程序中使用它。例如:让我们测试debug_switch变量(用于确定程序是否处于调试模式的开关)是否正确,并打印从文件中检索到的其他配置参数:
       if debug_switch == "True":
           print("The device id is " + device_id) 
           print("The sensor_address is " + sensor_address)

例 3

让我们讨论一个示例,其中我们希望修改现有的配置文件。这在执行固件更新后需要更新配置文件中的固件版本号的情况下特别有用。

以下代码片段可作为config_parser_modify.py与本章一起下载:

import configparser 

if __name__ == "__main__": 
   # initialize ConfigParser 
   config_parser = configparser.ConfigParser() 

   # Let's read the config file 
   config_parser.read('raspi.cfg') 

   # Set firmware version 
   config_parser.set('AppInfo', 'fw_version', 'A3') 

   # write the updated config to the config file 
   with open('raspi.cfg', 'w') as config_file: 
       config_parser.write(config_file)

让我们讨论一下它是如何工作的:

  1. 和往常一样,第一步是初始化ConfigParser类的实例。使用read方法加载配置文件:
       # initialize ConfigParser 
       config_parser = configparser.ConfigParser() 

       # Let's read the config file 
       config_parser.read('raspi.cfg')
  1. 使用set方法更新所需参数(在前面的示例中讨论):
       # Set firmware version 
       config_parser.set('AppInfo', 'fw_version', 'A3')
  1. 更新后的配置使用write方法保存到配置文件中:
       with open('raspi.cfg', 'w') as config_file: 
          config_parser.write(config_file)

以示例 3 为参考,将配置参数debug_switch更新为值False。重复例子 2,看看会发生什么。

在本节中,我们将讨论如何读取/写入 CSV 文件。本模块(https://docs.python.org/3.4/library/csv.html 在数据记录应用中非常有用。因为我们将在下一章讨论数据记录,所以让我们回顾一下对 CSV 文件的读/写。

让我们考虑一个场景,我们正在读取来自不同传感器的数据。该数据需要记录到 CSV 文件中,其中每列对应于特定传感器的读数。我们将讨论一个示例,其中我们将值123456789记录在 CSV 文件的第一行,第二行将由值组成,包括RedGreenBlue

  1. 写入 CSV 文件的第一步是使用with关键字打开 CSV 文件:
       with open("csv_example.csv", 'w') as csv_file:
  1. 下一步是初始化 CSV 模块的writer类的实例:
       csv_writer = csv.writer(csv_file)
  1. 现在,通过创建一个包含所有需要添加到行中的元素的列表,将每一行添加到文件中。例如:第一行可以添加到列表中,如下所示:
       csv_writer.writerow([123, 456, 789])
  1. 总而言之,我们有:
       import csv 
       if __name__ == "__main__": 
          # initialize csv writer 
          with open("csv_example.csv", 'w') as csv_file: 
                csv_writer = csv.writer(csv_file) 
                csv_writer.writerow([123, 456, 789]) 
                csv_writer.writerow(["Red", "Green", "Blue"])
  1. 当执行上述代码段时(可作为csv_write.py与本章一起下载),将在本地目录中创建一个 CSV 文件,其内容如下:
 123,456,789
 Red,Green,Blue

让我们讨论一个示例,在该示例中,我们阅读了上一节中创建的 CSV 文件的内容:

  1. 读取 CSV 文件的第一步是以读取模式打开它:
       with open("csv_example.csv", 'r') as csv_file:
  1. 接下来,我们从 CSV 模块初始化reader类的一个实例。CSV 文件的内容加载到对象csv_reader
       csv_reader = csv.reader(csv_file)
  1. 现在已加载 CSV 文件的内容,可以按如下方式检索 CSV 文件的每一行:
       for row in csv_reader: 
           print(row)
  1. 总而言之:
       import csv 

       if __name__ == "__main__": 
          # initialize csv writer 
          with open("csv_example.csv", 'r') as csv_file: 
                csv_reader = csv.reader(csv_file) 

                for row in csv_reader: 
                      print(row)
  1. 当执行前面的代码片段时(可作为csv_read.py与本章一起下载),文件的内容逐行打印,其中每行都是包含逗号分隔值的列表:
       ['123', '456', '789']
 ['Red', 'Green', 'Blue']

Python 附带了几个工具,可以与其他文件和操作系统本身进行交互。我们已经确定了我们在过去的项目中使用的所有 Python 工具。让我们讨论一下不同的模块及其用途,因为我们可能会在本书的最后一个项目中使用它们。

顾名思义,本模块(https://docs.python.org/3.1/library/os.html 允许与操作系统交互。让我们用例子来讨论它的一些应用。

os模块可用于检查特定目录中是否存在文件。例如:我们广泛使用了write_file.txt文件。在打开此文件进行读写之前,我们可以检查该文件是否存在:

import os
if __name__ == "__main__":
    # Check if file exists
    if os.path.isfile('/home/pi/Desktop/code_samples/write_file.txt'):
        print('The file exists!')
    else:
        print('The file does not exist!')

在前面的代码片段中,我们使用了os.path模块提供的isfile()函数。当一个文件的位置被传递一个参数给函数时,如果该文件存在于该位置,它将返回True。在本例中,由于文件write_file.txt存在于代码示例目录中,因此函数返回True。因此,信息The file exists被打印到屏幕上:

if os.path.isfile('/home/pi/Desktop/code_samples/write_file.txt'): 
    print('The file exists!') 
else: 
    print('The file does not exist!')

os.path.isfile()类似,还有一个函数名为os.path.isdir()。如果特定位置存在文件夹,则返回True。我们一直在审查 Raspberry Pi 桌面上名为code_samples的文件夹中的所有代码示例。其存在可通过以下方式确认:

# Confirm code_samples' existence 
if os.path.isdir('/home/pi/Desktop/code_samples'): 
    print('The directory exists!') 
else: 
    print('The directory does not exist!')

os模块还支持使用remove()功能删除文件。任何作为参数传递给函数的文件都将被删除。在文件 I/O部分,我们讨论了使用文本文件read_file.txt读取文件。让我们通过将文件作为参数传递给remove()函数来删除该文件:

os.remove('/home/pi/Desktop/code_samples/read_file.txt')

通过将进程pid传递给kill()函数,可以终止在 Raspberry Pi 上运行的应用程序。在上一章中,我们讨论了在 Raspberry Pi 上作为后台进程运行的light_scheduler示例。为了演示终止进程,我们将尝试终止该进程。我们需要确定light_scheduler流程的pid流程(您可以选择一个由您作为用户启动的应用程序,但不要接触根流程)。可使用以下命令从命令行终端检索进程pid

 ps aux

它吐出当前在 Raspberry Pi 上运行的进程(如下图所示)。light_scheduler申请的流程pid为 1815:

light_scheduler daemon's PID

假设我们知道需要终止的应用程序的进程pid,让我们使用kill()来回顾终止函数。终止函数所需的参数包括进程pid和需要发送到进程以终止应用程序的信号(signal.SIGKILL

import os
import signal
if __name__ == "__main__":
    #kill the application
    try:
        os.kill(1815, signal.SIGKILL)
    except OSError as error:
        print("OS Error " + str(error))

signal模块(https://docs.python.org/3/library/signal.html))包含表示可用于停止应用程序的信号的常数。在这个代码片段中,我们使用了SIGKILL信号。尝试运行ps命令(ps aux,您会注意到light_scheduler应用程序已被终止。

在前面的示例中,我们讨论了使用kill()函数终止应用程序。您可能已经注意到,我们使用了名为try/except的关键字试图终止应用程序。我们将在下一章详细讨论这些关键字。

还可以使用try/except关键字使用kill()功能监控应用程序是否正在运行。在介绍使用try/except关键字捕获异常的概念后,我们将讨论使用kill()功能的监控过程。

os模块中讨论的所有示例都可以作为os_utils.py随本章一起下载。

glob模块(https://docs.python.org/3/library/glob.html 允许识别特定扩展名的文件或具有特定模式的文件。例如,可以按如下方式列出文件夹中的所有 Python 文件:

# List all files
for file in glob.glob('*.py'):
    print(file)

glob()函数返回包含.py扩展名的文件列表。使用for循环遍历列表并打印每个文件。执行前面的代码段时,输出包含属于本章的所有代码示例的列表(输出被截断以表示):

read_from_file.py
config_parser_read.py
append_to_file.py
read_line_from_file.py
config_parser_modify.py
python_utils.py
config_parser_write.py
csv_write.py

本模块特别有助于列出具有特定模式的文件。例如:让我们考虑一个场景,您希望上传从实验的不同实验中创建的文件。您只对以下格式的文件感兴趣:file1xx.txt其中x表示09之间的任何数字。这些文件可以按如下方式排序和列出:

# List all files of the format 1xx.txt
for file in glob.glob('txt_files/file1[0-9][0-9].txt'):
    print(file)

在上例中,[0-9]表示文件名可以包含09之间的任何数字。由于我们正在查找file1xx.txt格式的文件,因此传递给glob()函数的参数的搜索模式是file1[0-9][0-9].txt

执行上述代码段时,输出包含指定格式的所有文本文件:

txt_files/file126.txt
txt_files/file125.txt
txt_files/file124.txt
txt_files/file123.txt
txt_files/file127.txt

我们看到这篇文章解释了如何使用表达式对文件进行排序:http://www.linuxjournal.com/content/bash-extended-globbing 。同样的概念可以扩展到使用glob模块搜索文件。

glob模块讨论的示例可与本章一起下载为glob_example.py。在其中一个示例中,我们讨论了列出特定格式的文件。您将如何列出以下格式的文件:filexxxx.*?(此处x表示09之间的任何数字。*表示任何文件扩展名。)

shutil模块(https://docs.python.org/3/library/shutil.html 允许使用move()copy()方法在文件夹之间移动和复制文件。在上一节中,我们列出了文件夹txt_files中的所有文本文件。让我们使用move()将这些文件移动到当前目录(执行代码的地方),在txt_files中再次复制这些文件,最后从当前目录中删除文本文件:

import glob
import shutil
import os
if __name__ == "__main__":
    # move files to the current directory
    for file in glob.glob('txt_files/file1[0-9][0-9].txt'):
        shutil.move(file, '.')
    # make a copy of files in the folder 'txt_files' and delete them
    for file in glob.glob('file1[0-9][0-9].txt'):
        shutil.copy(file, 'txt_files')
        os.remove(file)

在前面的示例中(与本章一起作为shutil_example.py下载),通过将源和目标分别指定为第一个和第二个参数,将文件从源移动和复制到目标。

使用glob模块识别要移动(或复制)的文件。然后,使用相应的方法移动或复制每个文件。

我们在前一章中简要讨论了该模块。subprocess模块(https://docs.python.org/3.2/library/subprocess.html 允许从 Python 程序中启动另一个程序。subprocess模块中常用的函数之一是Popen。需要从程序内部启动的任何进程都需要作为列表参数传递给Popen函数:

import subprocess
if __name__ == "__main__":
    subprocess.Popen(['aplay', 'tone.wav'])

在前面的示例中,tone.wav(需要播放的波形文件)和需要运行的命令作为列表参数传递给函数。来自subprocess模块的其他几个命令也有类似的用途。我们把它留给你去探索。

sys模块(https://docs.python.org/3/library/sys.html 允许与 Python 运行时解释器交互。sys模块的功能之一是解析作为程序输入提供的命令行参数。让我们编写一个程序,读取并打印作为参数传递给程序的文件内容:

import sys
if __name__ == "__main__":
    with open(sys.argv[1], 'r') as read_file:
        print(read_file.read())

尝试按如下方式运行前面的示例:

python3 sys_example.py read_lines.txt

上述示例与本章一起作为sys_example.py下载。运行程序时传递的命令行参数列表在sys模块中作为argv列表提供。argv[0]通常是 Python 程序的名称,argv[1]通常是传递给函数的第一个参数。

当以read_lines.txt为参数执行sys_example.py时,程序应打印文本文件的内容:

I am learning Python Programming using the Raspberry Pi Zero.
This is the second line.
Line 3.
Line 4.
Line 5.
Line 6.
Line 7.

在本章中,我们讨论了文件 I/O–读取和写入文件,以及用于读取、写入和追加文件的不同标志。我们讨论了将文件指针移动到文件中的不同点,以检索特定内容或覆盖特定位置的文件内容。我们讨论了 Python 中的ConfigParser模块及其在存储/检索应用程序的配置参数以及读取和写入 CSV 文件方面的应用。

最后,我们讨论了在我们的项目中有潜在用途的不同 Python 工具。在我们的最终项目中,我们将广泛使用文件 I/O 和讨论过的 Python 工具。我们强烈建议您在进入本书中讨论的最终项目之前,先熟悉本章中讨论的概念。

在接下来的章节中,我们将讨论将存储在 CSV 文件中的传感器数据上传到云中,以及在应用程序执行过程中遇到的日志错误。下一章见!

教程来源于Github,感谢apachecn大佬的无私奉献,致敬!

技术教程推荐

硅谷产品实战36讲 -〔曲晓音〕

趣谈网络协议 -〔刘超〕

软件设计之美 -〔郑晔〕

乔新亮的CTO成长复盘 -〔乔新亮〕

陈天 · Rust 编程第一课 -〔陈天〕

零基础入门Spark -〔吴磊〕

深入拆解消息队列47讲 -〔许文强〕

结构写作力 -〔李忠秋〕

结构执行力 -〔李忠秋〕