仓颉编程语言基础I/O操作详解
I/O流概述
仓颉编程语言将与应用程序外部载体交互的操作称为I/O操作,其中I对应输入(Input),O对应输出(Output)。仓颉所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字节数据的序列。
数据流是一串连续的数据集合,它就像承载数据的管道:在管道的一端输入数据,在管道的另一端就可以输出数据。仓颉将输入输出抽象为流(Stream)的概念:
-
输入流(InputStream):将数据从外存中读取到内存中的流。输入端可以一段一段地向管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。
-
输出流(OutputStream):将数据从内存写入外存中的流。输出端也可以一段一段地从管道中读出数据,每次可以读取其中的任意长度的数据(不需要跟输入端匹配),但只能按顺序读取先输入的数据。
仓颉使用Stream接口统一描述标准输入输出、文件操作、网络数据流、字符串流、加密流、压缩流等各种形式的I/O操作。Stream主要面向处理原始二进制数据,最小的数据单元是Byte。
数据流分类
按照数据流职责上的差异,仓颉将Stream分为两类:
节点流
节点流是直接提供数据源的流,其构造方式通常依赖于某种直接的外部资源(如文件、网络等)。常见的节点流包括:
- 标准流(StdIn/StdOut/StdErr):程序与外部数据交互的标准接口
- 文件流(File):对文件系统进行读写操作
- 网络流(Socket):网络通信的数据通道
处理流
处理流不能直接提供数据源,而是代理其他数据流进行处理,其构造方式依赖于其他流。常见的处理流包括:
- 缓冲流(BufferedInputStream/BufferedOutputStream):提供缓冲功能提高I/O性能
- 字符串流(StringReader/StringWriter):提供字符串处理能力
- 链式流(ChainedInputStream):顺序从多个输入流读取数据
节点流详解
标准流
标准流包含标准输入流(stdin)、标准输出流(stdout)和标准错误输出流(stderr),是程序与外部数据交互的标准接口:
- 程序运行时从输入流读取数据作为输入
- 程序输出信息被传送到输出流
- 错误信息被传送到错误流
在仓颉中可以使用Console类型访问标准流:
import std.io.* main() { // 从标准输入读取 let reader = Console.stdin let input = reader.readLine() // 向标准输出写入 let writer = Console.stdout writer.writeLine("Hello World") // 向标准错误写入 let errWriter = Console.stderr errWriter.writeLine("Error message") }
文件流
仓颉通过fs包支持通用文件系统操作,屏蔽不同操作系统的差异,提供统一的功能接口:
import std.fs.* main() { // 创建文件/目录 File.create("test.txt") Directory.create("tempDir") // 检查存在性 if (exists("test.txt")) { println("文件存在") } // 读写文件 let file = File.open("test.txt") file.write("Hello".toArray()) let content = file.readAll() // 删除文件/目录 remove("test.txt") remove("tempDir", recursive: true) }
文件流File类型同时提供常规文件操作和文件流两类功能:
- 常规文件操作:通过静态函数完成快捷操作
- 文件流功能:通过流接口进行细粒度控制
处理流详解
缓冲流
由于磁盘I/O相比内存I/O慢很多,对于高频次小数据量的读写,不带缓冲的数据流效率很低。缓冲流通过在内存中建立缓冲区,减少磁盘操作次数:
import std.io.* main() { let byteBuffer = ByteBuffer() byteBuffer.write("01234".toArray()) // 创建缓冲输出流 let bufferedOut = BufferedOutputStream(byteBuffer) bufferedOut.write("56789".toArray()) bufferedOut.flush() // 真正写入 println(String.fromUtf8(readToEnd(byteBuffer))) // 输出0123456789 }
BufferedInputStream和BufferedOutputStream通过内部缓冲区显著提升I/O性能:
- 写入时先放入内存缓冲区
- 读取时先从缓冲区获取
- 缓冲区满或主动flush时执行实际I/O
字符串流
仓颉的输入输出流基于字节数据抽象,在字符串处理场景不太友好。StringReader和StringWriter提供了更友好的字符串操作能力:
import std.io.* main() { // 字符串读取 let byteBuffer = ByteBuffer() byteBuffer.write("012\n346789".toArray()) let stringReader = StringReader(byteBuffer) let line = stringReader.readLine() // 读取一行 println(line ?? "error") // 输出012 // 字符串写入 let writer = StringWriter(byteBuffer) writer.write("Hello") writer.writeLine("Cangjie") }
字符串流的优势:
- 自动处理编码转换
- 提供按行读取等便捷方法
- 性能优于手动字节转换
I/O编程实践
文件复制示例
结合节点流和处理流实现文件复制:
import std.fs.* import std.io.* func copyFile(src: String, dest: String): Unit { let input = File.open(src) let output = File.create(dest) // 使用缓冲流提高性能 let bufferedIn = BufferedInputStream(input) let bufferedOut = BufferedOutputStream(output) let buf = Array<Byte>(4096, repeat: 0) while (bufferedIn.read(buf) > 0) { bufferedOut.write(buf) } bufferedOut.flush() input.close() output.close() }
标准流重定向
将标准输出重定向到文件:
import std.fs.* import std.io.* main() { let file = File.create("output.txt") let oldOut = Console.stdout // 重定向标准输出 Console.setOut(file.asOutputStream()) println("这将写入文件") // 恢复标准输出 Console.setOut(oldOut) println("这将打印到控制台") }
总结
仓颉编程语言的I/O系统通过流抽象提供了统一而强大的输入输出能力,主要特点包括:
- 流式处理:基于管道模型,支持分段读写
- 分层设计:节点流对接数据源,处理流增强功能
- 缓冲优化:减少实际I/O操作次数
- 统一接口:文件、网络、字符串等统一抽象
- 类型安全:严格的类型检查和错误处理
掌握仓颉的I/O系统需要理解流的概念和分类,熟悉常用节点流和处理流的特性及组合方式,才能在实际开发中构建高效可靠的I/O密集型应用。
更多推荐
所有评论(0)