个性化阅读
专注于IT技术分析

在Python教程中读写文件

本文概述

作为数据科学家, 你一定会处理大量数据!你将从多个来源, 数据库, Excel, 平面文件接收此数据。你将需要知道如何在平面文件中打开, 读取和写入数据, 以便可以对它们进行分析。

这正是本教程将介绍的内容!你将了解:

  • Python文件对象;
  • 如何打开文件, 以便可以访问数据;
  • 如何从文件中读取数据;
  • 访问数据后, 你也可以关闭文件
  • 并且还将数据写入文件;
  • 你还将看到一些Python文件对象属性,
  • 并看看File对象的其他方法
  • 最后, 你将深入研究Python os模块。

提示:如果你想了解有关在Python中导入文件的更多信息, 请查看srcmini的”在Python中导入数据”课程。

平面文件与文本文件

首先, 你首先应该知道什么是平面文件以及它们与文本文件的区别。

平面文件是包含记录的数据文件, 这些记录在记录之间没有结构化的关系, 也没有索引的结构, 就像你通常在关系数据库中找到它一样。这些文件只能包含基本格式, 具有固定的少量字段, 并且可以具有文件格式, 也可以不具有文件格式。

平面文件可以是纯文本文件或二进制文件。在前一种情况下, 文件通常每行包含一个记录:

  • 逗号分隔值(CSV)文件, 其中包含用分隔的数据值, 例如: 名称, 地址, 电子邮件ABC, 城市A, abc @ xyz.com LMN, 城市B, lmn @ xyz.com PQR, 城市C, pqr @ xyz.com
  • 带分隔符的文件, 其中包含带有用户指定的分隔符的数据值。这可以是\ t标签或符号(#, &, ||), 例如: 名称||地址||电子邮件ABC ||城市A||abc@xyz.com LMN ||城市B||lmn@xyz.com PQR ||城市C||pqr@xyz.com

但这对Python意味着什么?

Python文件对象

Python具有内置功能来创建和操作文件。 io模块是用于访问文件的默认模块, 你无需导入它。该模块由open(filename, access_mode)返回, 该文件返回一个文件对象, 该文件对象称为”句柄”。你可以使用此句柄读取或写入文件。 Python将文件视为对象, 它具有自己的属性和方法。

如前所述, 平面文件有两种类型:文本文件和二进制文件:

  1. 正如你阅读上一节所期望的那样, 文本文件具有行尾(EOL)字符以指示每行的终止。在Python中, 换行符(\ n)是默认的EOL终止符。
  2. 由于二进制文件在将数据转换为二进制语言(0和1)之后存储数据, 因此没有EOL字符。此文件类型返回字节。这是处理非文本文件(例如图像或exe)时要使用的文件。

在本教程中, 你将更多地关注文本文件。

打开()

内置的Python函数open()具有以下参数:

           `open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)`

上面的open()还会告诉每个参数的默认值。首先, 让我们动手操作使用前两个参数open(文件, 模式)读取和写入文件, 并逐个浏览其他参数。

注意, 在本教程中, 将不讨论opener, 因为它用于低级I / O操作。

文件

file是必须提供给open函数的参数。所有其他参数都是可选的, 并且具有默认值。现在, 此参数基本上是文件所在的路径。

如果路径在当前工作目录中, 则可以提供文件名, 如以下示例所示:

my_file_handle=open("mynewtextfile.txt")

如果文件位于该目录之外的目录中, 则必须提供具有文件名的完整路径:

my_file_handle=open("D:\\new_dir\\anotherfile.txt")
my_file_handle.read()
'Hi, \nI am in D Drive srcmini folder'

确保给定的文件名和路径正确, 否则会出现FileNotFoundError:

my_file_handle=open("D:\\new_dir1\\anotherfile.txt")
---------------------------------------------------------------------------

FileNotFoundError                         Traceback (most recent call last)

<ipython-input-3-f10ef385d072> in <module>()
----> 1 my_file_handle=open("D:\\new_dir1\\anotherfile.txt")


FileNotFoundError: [Errno 2] No such file or directory: 'D:\\new_dir1\\anotherfile.txt'

你可以使用try-finally块捕获异常:

try:
    my_file_handle=open("D:\\new_dir1\\anotherfile.txt")
except IOError:
    print("File not found or path is incorrect")
finally:
    print("exit")

存取模式

访问模式定义打开文件, 打开文件以只读, 只写或二者兼有的方式。它指定你要从哪个位置开始读取或写入文件。

你可以通过mode参数指定文件的访问模式。你使用默认模式” r”来读取文件。在其他要编写或附加的情况下, 分别使用” w”或” a”。

当然, 还有更多的访问模式!看一下下表:

字符 函数
[R 打开文件仅供读取。从文件开头开始读取。此默认模式。
rb 打开一个文件, 仅以二进制格式读取。从文件开头开始读取。
r+ 打开文件进行读写。文件指针放置在文件的开头。
打开文件仅用于写入。文件指针放置在文件的开头。覆盖现有文件, 如果不存在则创建一个新文件。
wb 与w相同, 但以二进制模式打开。
w+ 与w相同, 但也允许从文件读取。
wb + 与wb相同, 但也允许从文件读取。
一个 打开一个文件进行追加。在文件末尾开始写入。如果文件不存在, 则创建一个新文件。
ab 与a相同, 但采用二进制格式。如果文件不存在, 则创建一个新文件。
a+ 一样, 但也可以阅读。
从+ 相同的ab, 但也可以阅读。

正如你在第一部分中所看到的, 平面文件有两种类型, 这也是为什么还有一个选项可以指定要以哪种格式打开文件, 例如文本或二进制。当然, 前者是默认设置。

从文件读取

让我们尝试所有从文件读取的读取方法, 你还将一起探索访问模式!有三种读取文件的方法。

  • 读([n])
  • readline([n])
  • readlines()

注意:n是要读取的字节数。

创建如下文件:

1st line
2nd line
3rd line
4rth line
5th line

让我们看看每种读取方法的作用:

my_file=open("D:\\new_dir\\multiplelines.txt", "r")
my_file.read()

如果未在参数中给出字节数, 则read()方法仅输出整个文件。如果执行my_file.read(3), 你将获取文件的前三个字符

my_file=open("D:\\new_dir\\multiplelines.txt", "r")
my_file.read(3)

readline(n)输出文件单行最多n个字节。它读取的内容不超过一行。

my_file.close()
my_file=open("D:\\new_dir\\multiplelines.txt", "r")
#Use print to print the line else will remain in buffer and replaced by next statement
print(my_file.readline())
# outputs first two characters of next line
print(my_file.readline(2))

使用close()关闭Python文件

将close()方法与文件句柄一起使用以关闭文件。使用此方法时, 请清除所有缓冲区并关闭文件。

my_file.close()

你可以使用for循环逐行读取文件:

my_file=open("D:\\new_dir\\multiplelines.txt", "r")
#Use print to print the line else will remain in buffer and replaced by next statement
for line in my_file:
    print(line)
my_file.close()

readlines()方法维护文件中每行的列表:

my_file=open("D:\\new_dir\\multiplelines.txt", "r")
my_file.readlines()

写入文件

你可以使用以下三种方法在Python中写入文件:

  • write(string)(用于文本)或write(byte_string)(用于二进制)
  • 文字行(列表)

让我们在” D”驱动器的文件夹内创建一个新文件。以下操作将在指定的文件夹中创建一个新文件, 因为该文件不存在。请记住使用正确的文件名提供正确的路径, 否则会出现错误:

创建一个记事本文件, 并在其中写入一些文本。确保将文件另存为.txt并将其保存到Python的工作目录中。

my_file_handle=open("mynewtextfile.txt")
my_file_handle.read()
new_file=open("D:\\new_dir\\newfile.txt", mode="w", encoding="utf-8")
new_file.write("Writing to a new file\n")
new_file.write("Writing to a new file\n")
new_file.write("Writing to a new file\n")
new_file.close()

现在, 让我们使用a +模式将此文件写入列表:

fruits=["Orange\n", "Banana\n", "Apple\n"]
new_file=open("D:\\new_dir\\newfile.txt", mode="a+", encoding="utf-8")
new_file.writelines(fruits)
for line in new_file:
    print(line)
new_file.close()

请注意, 从文件读取不会打印任何内容, 因为文件光标位于文件的末尾。要在开始处设置光标, 可以使用文件对象的seek()方法:

cars=["Audi\n", "Bentely\n", "Toyota\n"]
new_file=open("D:\\new_dir\\newfile.txt", mode="a+", encoding="utf-8")
for car in cars:
    new_file.write(car)
print("Tell the byte at which the file cursor is:", new_file.tell())
new_file.seek(0)
for line in new_file:
    print(line)

文件对象的tell()方法告诉文件光标位于哪个字节。在seek(offset, reference_point)中, 参考点是0(文件的开头, 并且是默认值), 1(文件的当前位置)和2(文件的结尾)。

让我们尝试传递另一个参考点和偏移量, 然后查看输出:

new_file.seek(4, 0)
print(new_file.readline())
new_file.close()

请注意.seek()和.truncate()的使用:.truncate()中的参数为5, 表示将文件截断直到剩下5个字节的文本。输出显示正好剩下5个字节的文本, 包括空格。你只剩下next()方法, 因此让我们完成本节教程!在这里, 你使用的是上面创建的相同文件, 名称为multiplelines.txt。

如果文件模式不包括” b”(表示二进制格式), 则不允许使用诸如seek(-2, 2)之类的相对结束搜索。当将文件对象作为文本文件处理时, 仅允许诸如seek(0, 2)之类的转发操作。

file=open("D:\\new_dir\\multiplelines.txt", "r")
for index in range(5):
    line=next(file)
    print(line)
file.close()

请注意, write()实际上不会将数据写入文件, 但实际上会将数据写入缓冲区, 而是仅在调用close()时才写入。后一种方法刷新缓冲区并将内容写入文件。如果你不想关闭文件, 请使用fileObject.flush()方法清除缓冲区并写回文件。

你也可以将数据写入.json文件。

切记:Javascript Object Notation(JSON)已成为流行的方法, 可通过网络交换结构化信息并在平台之间共享信息。它基本上是具有某种结构的文本, 并将其保存为.json会告诉你如何读取结构, 否则它只是纯文本文件。它将数据存储为key:value对。结构可以简单到复杂。

看看以下针对国家及其首都的简单JSON:

{
"Algeria":"Algiers", "Andorra":"Andorra la Vella", "Nepal":"Kathmandu", "Netherlands":"Amsterdam", }

:之前的任何内容都称为键, 而:之后的任何内容均称为值。这与Python字典非常相似, 不是吗!你可以看到数据由分隔, 并且花括号定义了对象。方括号用于在更复杂的JSON文件中定义数组, 如以下摘录所示:

{
  "colors": [
    {
      "color": "black", "category": "hue", "type": "primary", "code": {
        "rgba": [255, 255, 255, 1], "hex": "#000"
      }
    }, {
      "color": "white", "category": "value", "code": {
        "rgba": [0, 0, 0, 1], "hex": "#FFF"
      }
    }, {
      "color": "red", "category": "hue", "type": "primary", "code": {
        "rgba": [255, 0, 0, 1], "hex": "#FF0"
      }
    }, {
      "color": "blue", "category": "hue", "type": "primary", "code": {
        "rgba": [0, 0, 255, 1], "hex": "#00F"
      }
    }, {
      "color": "yellow", "category": "hue", "type": "primary", "code": {
        "rgba": [255, 255, 0, 1], "hex": "#FF0"
      }
    }, {
      "color": "green", "category": "hue", "type": "secondary", "code": {
        "rgba": [0, 255, 0, 1], "hex": "#0F0"
      }
    }, ]
}

请注意, JSON文件也可以在一个对象中保存不同的数据类型!

使用read()读取文件时, 将从文件中读取字符串。这意味着在读取数字时, 需要使用int()这样的数据类型转换函数将它们转换为整数。对于更复杂的用例, 你始终可以使用json模块。

如果有一个对象x, 则可以用简单的代码行查看其JSON字符串表示形式:

# Importing json module
import json
my_data=["Hafsa Jabeen", "Reading and writing files in python", 78546]
json.dumps(my_data)

要将JSON写入文件中, 可以使用.dump()方法:

with open("jsonfile.json", "w") as f:
    json.dump(my_data, f)
f.close()

注意:最好使用with-open方法打开文件, 因为如果在途中出现任何异常, 它将正确关闭文件。这是尝试最终块的好选择。

已完成文件创建, 并已加载json包。如果打开了一个JSON文件以供读取, 则可以使用load(file)对其进行解码, 如下所示:

with open("jsonfile.json", "r") as f:
    jsondata=json.load(f)
    print(jsondata)
f.close()

同样, 可以使用json模块存储更复杂的字典。你可以在这里找到更多信息。

现在, 你将看到open()方法的其他一些参数, 在上一节中已经看到了。让我们从缓冲开始。

缓冲

缓冲区保留来自操作系统文件流的大量数据, 直到使用它来输入更多数据为止, 这类似于视频缓冲。

当你不知道正在使用的文件大小时, 缓冲很有用;如果文件大小大于计算机内存, 则处理单元将无法正常工作。缓冲区大小告诉你一次使用之前可以保留多少数据。io.DEFAULT_BUFFER_SIZE可以告诉你平台的默认缓冲区大小。

(可选)你可以将整数传递给缓冲以设置缓冲策略:

  1. 0以关闭缓冲(仅在二进制模式下允许)
  2. 1选择行缓冲(仅在文本模式下可用)
  3. 任何大于1的整数, 以指示固定大小的块缓冲区的字节大小
  4. 使用负值将缓冲策略设置为系统默认值

如果你未指定任何政策, 则默认值为:

  1. 二进制文件以固定大小的块缓冲
  2. 选择缓冲区的大小取决于底层设备的”块大小”。在许多系统上, 缓冲区的长度通常为4096或8192字节。
  3. “交互式”文本文件(isatty()返回True的文件)使用行缓冲。其他文本文件将上述策略用于二进制文件。请注意, isatty()可用于查看你是否已连接到类似Tele-TYpewriter()的设备。
import io
print("Default buffer size:", io.DEFAULT_BUFFER_SIZE)
file=open("mynewtextfile.txt", mode="r", buffering=5)
print(file.line_buffering)
file_contents=file.buffer
for line in file_contents:
    print(line)

请注意, 如果你按open(file, mode =’r’, buffering = -1, encoding = None, errors = None, newline = None, closefd = True, opener = None)中指定的顺序使用所有参数, 你无需编写参数名称!如果由于要保留默认值而跳过参数, 则最好将所有内容全部写完整。

错误

一个可选的字符串, 指定如何处理编码和解码错误。该参数不能在二进制模式下使用。可以使用多种标准错误处理程序(在”错误处理程序”下列出)。

file=open("mynewtextfile.txt", mode="r", errors="strict")
print(file.read())
file.close()

如果存在编码错误, errors =” strict”引发ValueErrorException。

新队

newline控制通用换行模式的工作方式(仅适用于文本模式)。可以是”无”, “”, ” \ n”, ” \ r”和” \ r \ n”。在上面的示例中, 你看到将None传递给换行符会将’\ r \ n’转换为’\ n’。

  1. 无:启用通用换行模式。输入中的行可以以’\ n’, ‘\ r’或’\ r \ n’结尾, 并将它们转换为默认的行分隔符
  2. “”:启用通用换行模式, 但不翻译返回行尾
  3. ‘\ n’, ‘\ r’, ‘\ r \ n’:输入行仅由给定的字符串终止, 并且行尾不进行翻译。

请注意, 通用换行符是一种解释文本流的方式, 其中, 以下所有字符均被视为结束行:Unix行尾约定’\ n’, Windows约定’\ r \ n’和旧的Macintosh约定’\ r’。

还要注意, os.linesep返回系统的默认行分隔符:

file=open("mynewtextfile.txt", mode="r", newline="")
file.read()
file=open("mynewtextfile.txt", mode="r", newline=None)
file.read()
file.close()

编码方式

encoding表示字符编码, 这是一种使用位和字节表示字符的编码系统。在谈论数据存储, 数据传输和计算时, 经常会出现这个概念。

由于默认编码取决于Microsoft Windows的操作系统, 因此默认编码为cp1252, 但在Linux中为UTF-8。因此, 在处理文本文件时, 最好指定字符编码。请注意, 二进制模式不使用编码参数。

之前, 你读到可以使用errors参数处理编码和解码错误, 并且可以使用换行符处理行尾。现在, 尝试以下代码:

with open("mynewtextfile.txt", mode="r") as file:
    print("Default encoding:", file.encoding)
    file.close()
##change encoding to utf-8
with open("mynewtextfile.txt", mode="r", encoding="utf-8") as file:
    print("New encoding:", file.encoding)
    file.close()

关闭

如果closefd为False且给出了文件描述符而不是文件名, 则在关闭文件时, 底层文件描述符将保持打开状态。如果提供了文件名, 则必须将closefd设置为True, 这是默认设置。否则, 你可能会得到一个错误。你可以使用此参数将现有文件描述符包装到实际文件对象中。

请注意, 文件描述符只是操作系统分配给文件对象的整数, 因此Python可以请求I / O操作。方法.fileno()返回此整数。

如果你已经为I / O通道打开了一个整数文件描述符, 则可以围绕它包装一个文件对象, 如下所示:

file=open("mynewtextfile.txt", "r+")
fd=file.fileno()
print("File descriptor assigned:", fd)

# Turn the file descriptor into a file object
filedes_object=open(fd, "w")
filedes_object.write("Data sciences\r\nPython")
filedes_object.close()

在这种情况下, filedes_object将关闭基础文件对象文件。关闭文件将提供OSError错误的文件描述符:

file.close()

为了防止关闭基础文件对象, 可以使用closefd = False:

file=open("mynewtextfile.txt", "r+")
fd=file.fileno()
print("File descriptor assigned:", fd)

# Turn the file descriptor into a file object
filedes_object=open(fd, "w", closefd=False)
filedes_object.write("Hello")
filedes_object.close()
file.close()

到目前为止, 你已经学到了很多有关使用Python读取文本文件的知识, 但是, 由于你在本教程中已经阅读了很多次, 所以这些并不是你可以导入的唯一文件:还有二进制文件。

但是这些二进制文件到底是什么?

二进制文件以机器可读的方式将数据存储在0和1中。一个字节是8位的集合。一个字符将一个字节存储在8位内存中。例如, 字符” H”的二进制表示形式是01001000, 然后将此8位二进制字符串转换为十进制, 则得出72。

binary_file=open("D:\\new_dir\\binary_file.bin", mode="wb+")
text="Hello 123"
encoded=text.encode("utf-8")
binary_file.write(encoded)
binary_file.seek(0)
binary_data=binary_file.read()
print("binary:", binary_data)
text=binary_data.decode("utf-8")
print("Decoded data:", text)

当你打开文件以二进制模式b进行读取时, 它将返回数据字节。

如果你需要从二进制文件中读取或写入文本, 请确保记得像上面那样对它进行解码或编码。你可以像下面这样通过迭代访问每个字节, 它将返回整数字节值(每个字符的8位二进制表示形式的十进制), 而不是字节字符串:

for byte in binary_data:
    print(byte)

Python文件对象属性

文件属性提供有关文件和文件状态的信息。

属性 函数
名称 返回文件名
关闭 如果文件已关闭, 则返回true。否则为假。
模式 文件打开的模式。
软空间 返回一个布尔值, 该布尔值指示在使用print语句时是否需要在另一个值之前打印空格字符。
编码方式 文件的编码
# This is just another way you can open  a file
with open("D:\\new_dir\\anotherfile.txt") as file:
    print("Name of the file:", file.name)
    print("Mode of the file:", file.mode)
    print("Mode of the file:", file.encoding)
    file.close()
print("Closed?", file.closed)

文件对象的其他方法

方法 函数
readable() 返回文件是否可读的True / False
writable() 文件是否可写返回True / False
fileno() 返回Python用来从操作系统请求I / O操作的Integer描述符
flush() 清除文件的内部缓冲区。
isatty() 如果文件连接到Teletytywriter(TTY)设备或类似设备, 则返回True。
truncate([size) 截断文件, 最多指定字节。
next(iterator, [default]) 当文件用作迭代器时, 对文件进行迭代;当到达文件末尾(EOF)进行读取时, 停止迭代。

让我们尝试所有这些方法:

with open("mynewtextfile.txt", "w+") as f:
    f.write("We are learning python\nWe are learning python\nWe are learning python")
    f.seek(0)
    print(f.read())
    print("Is readable:", f.readable())
    print("Is writeable:", f.writable())
    print("File no:", f.fileno())
    print("Is connected to tty-like device:", f.isatty())
    f.truncate(5)
    f.flush()
    f.seek(0)
    print(f.read())
f.close()

通过os模块处理文件

Python的os模块允许你执行与操作系统有关的操作, 例如制作文件夹, 列出文件夹的内容, 了解进程, 结束进程等。它具有查看Python所在操作系统的环境变量的方法。工作等等。这是os模块的Python文档。

让我们看一些有用的os模块方法, 这些方法可以帮助你处理程序中的文件和文件夹。

方法 函数
os.makedirs() 新建一个文件夹
os.listdir() 列出文件夹的内容
os.getcwd() 显示当前工作目录
os.path.getsize() 显示参数中传递的文件大小(以字节为单位)
os.path.isfile() 传递参数文件
os.path.isdir() 传递参数一个文件夹
os.chdir 更改目录/文件夹
os.rename(当前, 新) 重命名文件
os.remove(文件名) 删除档案

让我们看一下这些方法的一些例子:

import os
os.getcwd()
'C:\\Users\\HAFSA-J'
os.makedirs("D:\\my_folder")
---------------------------------------------------------------------------

FileExistsError                           Traceback (most recent call last)

<ipython-input-6-346b12771465> in <module>()
----> 1 os.makedirs("D:\\my_folder")


C:\Users\HAFSA-J\Anaconda3\lib\os.py in makedirs(name, mode, exist_ok)
    218             return
    219     try:
--> 220         mkdir(name, mode)
    221     except OSError:
    222         # Cannot rely on checking for EEXIST, since the operating system


FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'D:\\my_folder'

下一个代码块将在D驱动器中创建一个名为My_folder的文件夹:

open("D:\\my_folder\\newfile.txt", "w")
print("Contents of folder D:\\my_folder\n", os.listdir("D:\\my_folder"))
print("---------------------------------")
print("Size of folder D:\my_folder (in bytes)", os.path.getsize("D:\\my_folder"))
print("Is file?", os.path.isfile("D:\\new_dir"))
print("Is folder?", os.path.isdir("D:\\new_dir\\anotherfile.txt"))
os.chdir("D:\\my_folder")
os.rename("newfile.txt", "hello.txt")
print("New Contents of folder D:\\my_folder\n", os.listdir("D:\\my_folder"))
Contents of folder D:\my_folder
 ['hello.txt', 'newfile.txt']
---------------------------------
Size of folder D:\my_folder (in bytes) 0
Is file? False
Is folder? False



---------------------------------------------------------------------------

FileExistsError                           Traceback (most recent call last)

<ipython-input-9-4884bcddc38c> in <module>()
      6 print("Is folder?", os.path.isdir("D:\\new_dir\\anotherfile.txt"))
      7 os.chdir("D:\\my_folder")
----> 8 os.rename("newfile.txt", "hello.txt")
      9 print("New Contents of folder D:\\my_folder\n", os.listdir("D:\\my_folder"))


FileExistsError: [WinError 183] Cannot create a file when that file already exists: 'newfile.txt' -> 'hello.txt'

如果你创建的文件名已经存在, Python将给出FileExistsError错误。要删除使用的文件, 可以使用os.remove(filename):

os.getcwd()
os.remove("hello.txt")
print("New Contents of folder D:\\my_folder\n", os.listdir("D:\\my_folder"))
os.chdir("C:\\Users\\Hafsa-J")

这全都与平面文件有关!如果你想学习如何从Excel工作表中导入数据, 请查看本教程。

哇!

在开始之前, 你绝对应该检查Python的出色数据处理库熊猫:请参阅本教程, 以获取处理数据的更多好方法。

教程到此结束!现在你知道了如何在Python中处理文件以及从创建到操作系统级处理的操作。

赞(0)
未经允许不得转载:srcmini » 在Python教程中读写文件

评论 抢沙发

评论前必须登录!