文件
除了 Path
CLI 参数,您还可以声明一些类型的“文件”。
提示
在大多数情况下,您可能只需要使用 Path
就可以了。
您可以使用 Path
以相同的方式读取和写入数据。
区别在于这些类型将为您提供一个 Python 类文件对象,而不是一个 Python Path。
“类文件对象”与 open()
返回的相同类型的对象相同,例如
with open('file.txt') as f:
# Here f is the file-like object
read_data = f.read()
print(read_data)
但在某些特殊情况下,您可能希望使用这些特殊类型。例如,如果您正在迁移现有应用程序。
FileText
读取¶
typer.FileText
为您提供了一个用于读取文本的类文件对象,您将从中获得 str
数据。
这意味着即使您的文件包含以非英语语言编写的文本,例如一个包含以下内容的 text.txt
文件:
la cigüeña trae al niño
您将拥有一个包含文本的 str
,例如:
content = "la cigüeña trae al niño"
而不是拥有 bytes
,例如:
content = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o"
您将获得所有正确的编辑器支持、属性、方法等,用于类文件对象:
import typer
from typing_extensions import Annotated
def main(config: Annotated[typer.FileText, typer.Option()]):
for line in config:
print(f"Config line: {line}")
if __name__ == "__main__":
typer.run(main)
提示
如果可能,请优先使用 Annotated
版本。
import typer
def main(config: typer.FileText = typer.Option(...)):
for line in config:
print(f"Config line: {line}")
if __name__ == "__main__":
typer.run(main)
检查它
// Create a quick text config
$ echo "some settings" > config.txt
// Add another line to the config to test it
$ echo "some more settings" >> config.txt
// Now run your program
$ python main.py --config config.txt
Config line: some settings
Config line: some more settings
FileTextWrite
¶
要写入文本,您可以使用 typer.FileTextWrite
import typer
from typing_extensions import Annotated
def main(config: Annotated[typer.FileTextWrite, typer.Option()]):
config.write("Some config written by the app")
print("Config written")
if __name__ == "__main__":
typer.run(main)
提示
如果可能,请优先使用 Annotated
版本。
import typer
def main(config: typer.FileTextWrite = typer.Option(...)):
config.write("Some config written by the app")
print("Config written")
if __name__ == "__main__":
typer.run(main)
这将用于写入人类文本,例如
some settings
la cigüeña trae al niño
...而不是写入二进制 bytes
。
检查它
$ python main.py --config text.txt
Config written
// Check the contents of the file
$ cat text.txt
Some config written by the app
技术细节
typer.FileTextWrite
只是一个便利类。
它与使用 typer.FileText
并设置 mode="w"
相同。您将在下面了解有关 mode
的更多信息。
FileBinaryRead
¶
要读取二进制数据,您可以使用 typer.FileBinaryRead
。
您将从中收到 bytes
。
它对于读取二进制文件(如图像)很有用
import typer
from typing_extensions import Annotated
def main(file: Annotated[typer.FileBinaryRead, typer.Option()]):
processed_total = 0
for bytes_chunk in file:
# Process the bytes in bytes_chunk
processed_total += len(bytes_chunk)
print(f"Processed bytes total: {processed_total}")
if __name__ == "__main__":
typer.run(main)
提示
如果可能,请优先使用 Annotated
版本。
import typer
def main(file: typer.FileBinaryRead = typer.Option(...)):
processed_total = 0
for bytes_chunk in file:
# Process the bytes in bytes_chunk
processed_total += len(bytes_chunk)
print(f"Processed bytes total: {processed_total}")
if __name__ == "__main__":
typer.run(main)
检查它
$ python main.py --file lena.jpg
Processed bytes total: 512
Processed bytes total: 1024
Processed bytes total: 1536
Processed bytes total: 2048
FileBinaryWrite
¶
要写入二进制数据,您可以使用 typer.FileBinaryWrite
。
您将向其写入 bytes
。
它对于写入二进制文件(如图像)很有用。
请记住,您必须将 bytes
传递给它的 .write()
方法,而不是 str
。
如果您有 str
,您必须先对其进行编码以获得 bytes
。
import typer
from typing_extensions import Annotated
def main(file: Annotated[typer.FileBinaryWrite, typer.Option()]):
first_line_str = "some settings\n"
# You cannot write str directly to a binary file, you have to encode it to get bytes
first_line_bytes = first_line_str.encode("utf-8")
# Then you can write the bytes
file.write(first_line_bytes)
# This is already bytes, it starts with b"
second_line = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o"
file.write(second_line)
print("Binary file written")
if __name__ == "__main__":
typer.run(main)
提示
如果可能,请优先使用 Annotated
版本。
import typer
def main(file: typer.FileBinaryWrite = typer.Option(...)):
first_line_str = "some settings\n"
# You cannot write str directly to a binary file, you have to encode it to get bytes
first_line_bytes = first_line_str.encode("utf-8")
# Then you can write the bytes
file.write(first_line_bytes)
# This is already bytes, it starts with b"
second_line = b"la cig\xc3\xbce\xc3\xb1a trae al ni\xc3\xb1o"
file.write(second_line)
print("Binary file written")
if __name__ == "__main__":
typer.run(main)
$ python main.py --file binary.dat
Binary file written
// Check the binary file was created
$ ls ./binary.dat
./binary.dat
文件CLI 参数配置¶
您可以在 typer.Option()
和 typer.Argument()
中为这些类型(类)使用多个配置参数
mode
:控制用于打开文件的 "模式"。- 通过使用上面的类,它会自动为您设置。
- 阅读下面有关它的更多信息。
encoding
:强制使用特定编码,例如"utf-8"
。lazy
:延迟 I/O 操作。默认情况下自动执行。- 默认情况下,在写入文件时,Click 将生成一个尚未成为实际文件的类文件对象。一旦您开始写入,它将打开文件并开始写入,但不会在此之前。这主要用于避免在开始写入之前创建文件。通常将此设置为自动是安全的。但是,您可以通过设置
lazy=False
来覆盖它。默认情况下,对于写入,它是lazy=True
,对于读取,它是lazy=False
。
- 默认情况下,在写入文件时,Click 将生成一个尚未成为实际文件的类文件对象。一旦您开始写入,它将打开文件并开始写入,但不会在此之前。这主要用于避免在开始写入之前创建文件。通常将此设置为自动是安全的。但是,您可以通过设置
atomic
: 如果为真,所有写入操作实际上都会写入一个临时文件,并在完成后移动到最终目标。这对于由多个用户/程序频繁修改的文件很有用。
高级 mode
¶
默认情况下,Typer 会为您配置 mode
typer.FileText
:mode="r"
,用于读取文本。typer.FileTextWrite
:mode="w"
,用于写入文本。typer.FileBinaryRead
:mode="rb"
,用于读取二进制数据。typer.FileBinaryWrite
:mode="wb"
,用于写入二进制数据。
关于 FileTextWrite
的说明¶
typer.FileTextWrite
实际上只是一个方便类。它与使用 typer.FileText
和 mode="w"
相同。
但它可能更短、更直观,因为您可以在编辑器中通过只开始输入 typer.File
来获得它...就像其他类一样。
自定义 mode
¶
您可以覆盖上述默认值中的 mode
。
例如,您可以使用 mode="a"
将内容“追加”到同一个文件。
import typer
from typing_extensions import Annotated
def main(config: Annotated[typer.FileText, typer.Option(mode="a")]):
config.write("This is a single line\n")
print("Config line written")
if __name__ == "__main__":
typer.run(main)
提示
如果可能,请优先使用 Annotated
版本。
import typer
def main(config: typer.FileText = typer.Option(..., mode="a")):
config.write("This is a single line\n")
print("Config line written")
if __name__ == "__main__":
typer.run(main)
提示
由于您手动设置了 mode="a"
,您可以使用 typer.FileText
或 typer.FileTextWrite
,两者都可以工作。
检查它
$ python main.py --config config.txt
Config line written
// Run your program a couple more times to see how it appends instead of overwriting
$ python main.py --config config.txt
Config line written
$ python main.py --config config.txt
Config line written
// Check the contents of the file, it should have each of the 3 lines appended
$ cat config.txt
This is a single line
This is a single line
This is a single line
关于不同类型¶
信息
这些是关于 **Typer** 提供的不同类型/类的技术细节。
但您不需要这些信息就能使用它们。您可以跳过它。
**Typer** 为您提供这些不同的类型(类),因为它们直接继承自实际的 Python 实现,这些实现将在每种情况下提供。
这样,您的编辑器将为每种类型提供正确的类型检查和完成。
即使您使用lazy
。当您使用lazy
时,Click 会创建一个特殊的对象来延迟写入,并充当将要写入的实际文件的“代理”。但这个特殊的代理对象不公开编辑器类型检查和自动完成所需的属性和方法。如果您访问这些属性或调用这些方法,“代理”延迟对象将在最终对象中调用它们,并且一切都会正常工作。但您不会获得它们的自动完成。
但由于这些Typer类继承自将在其下方提供的实际实现(而不是延迟对象),因此您将在编辑器中获得所有自动完成和类型检查。