仓颉语言 -- 基础 I/O 操作

使用新版本 (2024-07-19 16:10发布的)

1、I/O 流概述

本章我们会介绍基本的 I/O 概念和文件操作。

在仓颉编程语言中,我们将与应用程序外部载体交互的操作称之为 I/O 操作I 对应输入(Input),O 对应输出(Output)。

仓颉编程语言所有的 I/O 机制都是基于数据流进行输入输出,这些数据流表示了字节数据的序列。数据流是一串连续的数据集合,它就像承载数据的管道,在管道的一端输入数据,在管道的另一端就可以输出数据。

仓颉编程语言将输入输出抽象为流(Stream):

  • 将数据从外存中读取到内存中的称为输入流(InputStream),输入端可以一段一段地向管道中写入数据,这些数据段会按先后顺序形成一个长的数据流;
  • 将数据从内存写入外存中的称为输出流(OutputStream),输出端也可以一段一段地从管道中读出数据,每次可以读取其中的任意长度的数据(不需要跟输入端匹配),但只能读取先输入的数据,再读取后输入的数据。

有了这一层抽象,仓颉编程语言就可以使用统一的接口来实现与外部数据的交互。

仓颉编程语言将标准输入输出文件操作网络数据流字符串流加密流压缩流等等形式的操作,统一用 Stream 描述。

Stream 主要面向处理原始二进制数据,Stream 中最小的数据单元是 Byte

仓颉编程语言将 Stream 定义成了 interface,它让不同的 Stream 可以用装饰器模式进行组合,极大地提升了可扩展性

1.1 输入流

程序从输入流读取数据源(数据源包括外界的键盘文件网络…),即输入流是将数据源读入到程序的通信通道

仓颉编程语言用 InputStream 接口类型来表示输入流,它提供了 read 函数,这个函数会将可读的数据写入到 buffer 中,返回值表示了该次读取的字节总数

InputStream 接口定义:

interface InputStream {
   
    func read(buffer: Array<Byte>): Int64
}

当我们拥有一个输入流的时候,就可以像下面的代码那样去读取字节数据,读取的数据会被写到 read 的入参数组中。

输入流读取示例:

import std.io.InputStream

main() {
   
    let input: InputStream = ...
    let buf = Array<Byte>(256, item: 0)
    while (input.read(buf) > 0) {
   
        println(buf)
    }
}

1.2 输出流

程序向输出流写入数据。输出流是将程序中的数据输出到外界(显示器打印机文件网络等)的通信通道。

仓颉编程语言用 OutputStream 接口类型来表示输出流,它提供了 write 函数,这个函数会将 buffer 中的数据写入到绑定的流中

特别的,有一些输出流的 write 不会立即写到外存中,而是有一定的缓冲策略,只有当符合条件主动调用 flush 时才会真实写入,目的是提高性能

为了统一处理这些 flush 操作,在 OutputStream 中有一个 flush 的默认实现,它有助于抹平 API 调用的差异性。

OutputStream 接口定义:

interface OutputStream {
   
    func write(buffer: Array<Byte>): Unit

    func flush(): Unit {
   
        // 空实现
    }
}

当我们拥有一个输出流时,我们可以像下面的代码那样去写入字节数据。

输出流写入示例:

import std.io.OutputStream

main() {
   
    let output: OutputStream = ...
    let buf = Array<Byte>(256, item: 111)
    output.write(buf)
    output.flush()
}

1.3 数据流分类

按照数据流职责上的差异,我们可以给 Stream 简单分成两类:

  • 节点流:直接提供数据源,节点流的构造方式通常是依赖某种直接的外部资源(即文件、网络等)。
  • 处理流:只能代理其它数据流进行处理,处理流的构造方式通常是依赖其它的流。

2、I/O 节点流

节点流是指直接提供数据源的流,节点流的构造方式通常是依赖某种直接的外部资源(即文件、网络等)。

仓颉编程语言中常见的节点流包含标准流(StdIn、StdOut、StdErr)、文件流(File)、网络流(Socket)等

我们本章会着重介绍一下标准流和文件流。

2.1 标准流

标准流包含了标准输入流(stdin)、标准输出流(stdout)和标准错误输出流(stderr)

标准流是我们的程序与外部数据交互的标准接口。程序运行的时候从输入流读取数据,作为程序的输入,程序运行过程中输出的信息被传送到输出流,类似的,错误信息被传送到错误流。

在仓颉编程语言中我们可以使用 Console 类型来分别访问它们

使用 Console 类型需要导入 console 包

导入 console 包示例:

import std.console.*

Console 对三个标准流都进行了易用性封装,提供了更方便的基于 String 的扩展操作,并且对于很多常见类型都提供了丰富的重载来优化性能

其中最重要的是 Console 提供了并发安全的保证,我们可以在任意线程中安全的通过 Console 提供的接口来读写内容。

默认情况下标准输入流来源于键盘输入的信息,例如我们在命令行界面中输入的文本。

当我们需要从标准输入流中获取数据时,可以通过 stdIn 来读取,例如通过 readln 函数来获取命令行的输入。

标准输入流读取示例:

import std.console.*

main() {
   
    let txt = Console.stdIn.readln()
    println(txt ?? "")
}

运行上面的代码,在命令行上输入一些文字,然后换行结束,我们就能看到我们输入的内容了!

输出流分为标准输出流标准错误流,默认情况下,它们都会输出到屏幕,例如我们在命令行界面中看到的文本。

当我们需要往标准输出流中写入数据时,可以通过 stdOut/stdErr 来写入,例如通过 write 函数来向命令打印内容。

使用 stdOut 和直接使用 print 函数的差别是,stdOut 是并发安全的,并且由于 stdOut 使用了缓存技术,在输入内容较多时拥有更好的性能表现。

需要注意的是,写完数据后我们需要对 stdOut 调用 flush 才能保证内容被写到标准流中。

标准输出流写入示例:

import std.console.*

main() {
   
    for (i in 0..1000) {
   
        Console.stdOut.writeln("hello, world!")
    }
    Console.stdOut.flush()
}

2.2 文件流

仓颉编程语言提供了 fs 包来支持通用文件系统任务。虽然不同的操作系统对于文件系统提供的接口有所不同,但是仓颉编程语言抽象出以下一些共通的功能,通过统一的功能接口,屏蔽不同操作系统之间的差异,来简化我们的使用。

这些常规操作任务包括:创建文件/目录、读写文件重命名或移动文件/目录、删除文件/目录、复制文件/目录、获取文件/目录元数据、检查文件/目录是否存在具体 API 可以查阅库文档。

使用文件系统相关的功能需要导入 fs 包

导入 fs 包示例:

import std.fs.*

本章会着重介绍 File 相关的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值