浙江传媒学院 · 仓颉面向对象程序设计 · 基于 CangStream 框架构建
浙江传媒学院 · 仓颉面向对象程序设计 · 基于 CangStream 框架构建
9.1.1 数据流(Stream);9.1.2 数据流分类;9.1.3 数据流操作;9.1.4 数据流操作异常。本节为理论内容。
9.1:使用 getStdIn()/getStdOut() 实现控制台输入输出交互。
package demo
import std.env.*
main() {
getStdOut().write("请输入您的名字:")
var namein = getStdIn().readln() // 输入:abc
var nameget= namein.getOrThrow()
getStdOut().write("您的名字为:")
getStdOut().writeln(nameget)
getStdOut().writeln("${nameget},您好,您的注册信息已经收到,欢迎您的光临!")
return
}
9.2.1:copy() 函数将输入流中的数据复制到输出流中,返回复制的字节数。
package demo
import std.io.ByteBuffer
import std.io.copy
main(): Unit {
let sourceStream = ByteBuffer()
let targetStream = ByteBuffer()
let mystring="仓颉面向对象程序设计语言"
/* 向源输入流写入数据 */
let sourceData = mystring.toArray()
sourceStream.write(sourceData)
/* 使用 copy 函数将源输入流的数据拷贝到目标输出流 */
let copiedBytes = copy(sourceStream, to: targetStream)
println("向目标区域拷贝的数据大小是${copiedBytes} 字节.")
/* 读取目标输出流中的数据 */
let targetData: Array<Byte> = Array<Byte>(sourceData.size, repeat: 0)
targetStream.read(targetData)
println("目标区域收到的数据是: ${String.fromUtf8(targetData)}")
}
9.2.2:readString() 读取输入流中所有剩余内容为字符串,非法 UTF-8 字节将抛出 ContentFormatException。
package demo
import std.io.ByteBuffer
import std.io.readString
import std.io.ContentFormatException
main(): Unit {
let inputStream = ByteBuffer()
let mystring="仓颉面向对象程序设计语言"
/* 向输入流写入数据 */
let sourceData = mystring.toArray()
inputStream.write(sourceData)
/* 使用 readString 函数读取输入流中的所有剩余内容 */
try {
let result = readString(inputStream)
println("读取字符串: ${result}")
} catch (e: ContentFormatException) {
println("Error: ${e.message}")
}
/* 向输入流写入一个不合法的 UTF-8 字符串 */
let sourceDataError: Array<UInt8> = [0xC3, 0x28]
inputStream.write(sourceDataError)
/* 使用 readString 函数读取输入流中的所有剩余内容 */
try {
let result = readString(inputStream)
println("读取字符串: ${result}")
} catch (e: ContentFormatException) {
println("错误: ${e.message}")
}
}
9.2.3:readStringUnchecked() 与 readString() 类似但不做合法性检查,unsafe 块中使用。
package demo
import std.io.ByteBuffer
import std.io.readStringUnchecked
main(): Unit {
let inputStream = ByteBuffer()
let mystring="Hello, World!"
/* 向输入流写入数据 */
let sourceData = mystring.toArray()
inputStream.write(sourceData)
/* 使用 readStringUnchecked 函数读取输入流中的所有剩余内容 */
unsafe {
let result = readStringUnchecked(inputStream)
println("读取字符: ${result}") }
/* 向输入流写入一个不合法的 UTF-8 字符串 */
let sourceDataError: Array<UInt8> = [0xC3, 0x28, 0x48, 0x65, 0x6C, 0x6C, 0x6F]
inputStream.write(sourceDataError)
/* 使用 readStringUnchecked 函数读取输入流中的所有剩余内容 */
unsafe {
let result = readStringUnchecked(inputStream)
println("读取字符: ${result}")
}
}
9.2.4:readToEnd() 读取输入流中所有剩余数据,返回一个字节数组。
package demo
import std.io.ByteBuffer
import std.io.readToEnd
main(): Unit {
let inputStream = ByteBuffer()
/* 向输入流写入数据 */
let sourceData = "你好, 仓颉!".toArray()
inputStream.write(sourceData)
/* 使用 readToEnd 函数读取输入流中的所有剩余内容 */
let data = readToEnd(inputStream)
println("${String.fromUtf8(data)}")
}
9.3.1:atExit() 注册进程退出时执行的清理函数,exit() 退出当前进程。
package demo
import std.env.*
func saygoodbye() {
println("程序执行完毕,再见")
}
main() {
atExit(saygoodbye) // 注册清理函数
println("程序执行中.....")
exit(1) // 程序退出,cleanup() 将被执行
return 0
}
9.3.1:getCommand() 获取当前进程的命令(可执行文件路径)。
package demo
import std.env.*
main() {
try {
let command = getCommand()
println("Process command: ${command}")
} catch (e: EnvException) {
println("Error: ${e.message}")
}
}
9.3.1:getCommandLine() 获取当前进程的命令行,包含命令及所有参数。
package demo
import std.env.*
main() {
try {
let commandLine = getCommandLine()
println("Command line: ${commandLine}")
} catch (e: EnvException) {
println("Error: ${e.message}")
}
}
9.3.1:使用标准输入/输出流实现多次交互式控制台输入输出。
package demo
import std.env.*
main() {
getStdOut().write("请输入信息1:")
var c = getStdIn().readln().getOrThrow() // 输入:你好,请问今天星期几?
getStdOut().writeln("输入的信息1为:" +c )
getStdOut().write("请输入信息2:")
c = getStdIn().readln().getOrThrow()// 输入:你好,请问今天几号?
getStdOut().writeln("输入的信息2为:" + c)
return
}
9.3.2:exists() 函数检查指定路径的文件是否存在。
package demo
import std.fs.*
main() {
let exist = exists("./src/character.txt")
println("exist: ${exist}")
}
// 注意:文件系统如下:
// src
// `-- main.cj
// `-- character.txt
// `--readstrok.cj
// target
// `-- release
// |-- .build-logs
// | |-- demo.errlog
// | `-- demo.outlog
// |-- bin
// | |-- demo.errlog
// | |--main.exe
// |-- demo
9.3.2:使用 move()、copy()、delete() 等函数进行文件操作。
package demo
import std.fs.*
main() {
let srcPath = "./src/characters.txt"
let destPath = "./src/character.txt"
try {
// 检查源文件是否存在
if (exists(srcPath)) {
println("文件已经存在,准备删除...")
remove(srcPath)
}
// 复制文件
if (exists(destPath)) {
copy(destPath, to: srcPath, overwrite: true)
println("文件复制完成")
}
} catch (e: Exception) {
println("操作失败: ${e.message}")
}
}
9.3.2:File.readFrom() 一次性读取文件所有数据,File.writeTo() 写入数据。
package demo
import std.fs.*
main() {
// 一次性读取文件所有数据
let bytes = File.readFrom("./src/characters.txt")
// 将数据写入到另一个文件
File.writeTo("./src/charactor.txt", bytes)
}
9.3.2:File.create() 创建文件实例,file.write() 将数据写入文件。
package demo
internal import std.fs.*
internal import std.io.*
main() {
// 创建一个文件实例
let file = File.create("./src/啊.txt")
let an="82,-64,0,-13,-12,-7,-12,-9,-3,-7,1,-6,4,-7,7,-10,7,-11,6,-64,0,-13,-12,-13,13,-13,13,-64,0,-4,-12,13,-12,13,-12,-64,0,10,-12,10,-12,-64,0,10,-12,10,11,9,12,3,12,3,12,-64,0,-2,-6,-2,7,-2,7,-64,0,-2,-5,-2,-5,5,-5,5,4,5,4,-64,0,-1,4,4,4,4,4,-64,-64,"
file.write(an.toArray())
}
9.4.1:BufferedInputStream 和 BufferedOutputStream 缓冲流的使用,flush() 刷新缓冲区。
package demo
import std.io.*
main(): Unit {
// 模拟数据源
let arr = "hello buffer".toArray()
let byteBuffer = ByteBuffer()
byteBuffer.write(arr)
// 使用带缓冲的输入流
let bis = BufferedInputStream(byteBuffer)
let buf = Array<Byte>(20, repeat: 0)
let n = bis.read(buf)
println(String.fromUtf8(buf[..n])) // hello buffer
// 使用带缓冲的输出流
let outBuffer = ByteBuffer()
let bos = BufferedOutputStream(outBuffer)
bos.write("world".toArray())
bos.flush() // 必须 flush 才会写入
println(String.fromUtf8(readToEnd(outBuffer))) // world
}
9.4.2:StringReader 按行读取字符串,StringWriter 写字符串,比字节操作更便捷。
package demo
import std.io.*
main(): Unit {
// StringReader 按行读取
let inputBuf = ByteBuffer()
inputBuf.write("line1\nline2\nline3".toArray())
let reader = StringReader(inputBuf)
println(reader.readln() ?? "error") // line1
println(reader.readln() ?? "error") // line2
// StringWriter 写字符串
let outputBuf = ByteBuffer()
let writer = StringWriter(outputBuf)
writer.write("hello")
writer.writeln(" world")
writer.write(123)
writer.flush()
println(String.fromUtf8(readToEnd(outputBuf)))
// hello world\n123
}
9.5.1-9.5.3:自定义 FatherException/ChildException 异常类,throw 抛出异常,try-catch 捕获处理。
package demo
import std.io.*
import std.fs.*
open class FatherException <: Exception {
public init() {
super("This is FatherException.")
}
public init(message: String) {
super(message)
}
public open override func getClassName(): String {
"FatherException"
}
}
class ChildException <: FatherException {
public init() {
super("This is ChildException.")
}
public override func getClassName(): String {
"ChildException"
}
}
// 以下是第一个例子
main() {
try {
throw NegativeArraySizeException("I am an Exception!")
} catch (e: NegativeArraySizeException) {
println(e)
println("NegativeArraySizeException is caught!")
}
println("This will also be printed!")
}
// 以下是第二个例子
// main() {
// try {
// throw NegativeArraySizeException("NegativeArraySizeException")
// } catch (e: NegativeArraySizeException) {
// println("Exception info: ${e}.")
// } finally {
// println("The finally block is executed.")
// }
// }
9.5.4:Resource 接口实现自动资源管理,try 块结束后自动调用 close() 方法释放资源。
// 第一个例子
package demo
import std.io.*
class R <: Resource {
public func isClosed(): Bool {
true
}
public func close(): Unit {
print("R is closed")
}
}
main() {
try (r = R()) {
println("Get the resource")
}
}
// 第二个例子
package demo
class R <: Resource {
public func isClosed(): Bool {
return true
}
public func close(): Unit {
print("R is closed")
}
}
main() {
try (r = R()) {
println("Get the resource")
} catch (e: Exception) {
println("Exception happened when executing the try-with-resources expression")
} finally {
println("End of the try-with-resources expression")
}
}
9.5.4:Worker 类实现 Resource 接口,演示工具借还场景中的自动资源管理与异常处理。
package demo
import std.io.*
class Worker <: Resource {
var hasTools: Bool = false
let name: String
public init(name: String) {
this.name = name
}
public func getTools() {
println("${name} picks up tools from the warehouse.")
hasTools = true
}
public func work() {
if (hasTools) {
println("${name} does some work with tools.")
} else {
println("${name} doesn't have tools, does nothing.")
}
}
public func isClosed(): Bool {
if (hasTools) {
println("${name} hasn't returned the tool.")
false
} else {
println("${name} has no tools")
true
}
}
public func close(): Unit {
println("${name} returns the tools to the warehouse.")
hasTools = false
}
}
main() {
try (r = Worker("Tom")) {
r.getTools()
r.work()
}
try (r = Worker("Bob")) {
r.work()
}
try (r = Worker("Jack")) {
r.getTools()
throw Exception("Jack left, because of an emergency.")
}
}
9.6.1:模式匹配处理 Option 类型,match-case 分别处理 Some 和 None。
package demo
import std.io.*
func getString(p: ?Int64): String {
match (p) {
case Some(x) => "${x}"
case None => "none"
}
}
main() {
let a = Some(1)
let b: ?Int64 = None
let r1 = getString(a) // r1 = "1"
let r2 = getString(b) // r2 = "none"
println(r1)
println(r2)
}
9.6.2:?? 操作符在值为 None 时提供默认值,简化 Option 类型的处理。
package demo
main() {
let a = Some(1)
let b:?Int64 = None
let r1:Int64 = a??0
let r2:Int64 = b??0
println(r1)
println(r2)
}
9.6.3:? 操作符用于安全访问 Option 内部成员,值为 None 时返回 None。
package demo
struct R {
public var a: Int64
public init(a: Int64) {
this.a = a
}
}
main() {
let r = R(100)
let x = Some(r)
let y = Option<R>.None
let r1 = x?.a // r1 = Option<Int64>.Some(100)
let r2 = y?.a // r2 = Option<Int64>.None
println(r1) // Some(100)
println(r2) // None
}
9.6.4:getOrThrow() 从 Option 中取值,如果是 None 则抛出 NoneValueException 异常。
package demo
func getOrThrow(a: ?Int64) {
match (a) {
case Some(v) => v
case None => throw NoneValueException() // 抛出异常
}
}
main() {
let a = Some(1)
let b: ?Int64 = None
let r1 = a.getOrThrow() // r1 = 1
println(r1)
try {
let r2 = b.getOrThrow() // 抛出异常
} catch (e: NoneValueException) {
println("b is None")
}
}
读取 score.txt 文件中的学生成绩数据,计算平均分并显示。
package demo
import std.fs.*
import std.convert.*
main() {
let path = "./src/score.txt"
try {
// 写入文件
let data = "张三 85\n李四 92\n王五 76".toArray()
File.writeTo(path, data)
// 读取文件
let bytes = File.readFrom(path)
let content = String.fromUtf8(bytes)
println("文件内容:\n${content}")
// 计算平均分
let lines = content.split("\n")
var total = 0
var count = 0
for (line in lines) {
if (line != "") {
let parts = line.split(" ")
total += Int64.parse(parts[1])
count++
}
}
println("平均分: ${total / count}")
} catch (e: Exception) {
println("读取文件失败: ${e.message}")
}
}
模拟日志备份,将 log.txt 的内容复制到 log_backup.txt,输出复制的字节数。
package demo
import std.io.copy
import std.fs.*
main() {
let srcPath = "./src/log.txt"
let destPath = "./src/log_backup.txt"
// 写入日志
let log = "系统启动成功...\n用户已登录...\n数据处理完成.".toArray()
File.writeTo(srcPath, log)
// 打开文件流
let srcFile = File(srcPath, Read)
let destFile = File(destPath, Write)
// 使用 copy 复制数据
let copied = copy(srcFile, to: destFile)
println("已复制 ${copied} 字节数据到 log_backup.txt")
// 验证读取
let bytes = File.readFrom(destPath)
println("备份内容:\n${String.fromUtf8(bytes)}")
}
''计算用户输入两数的商,除零异常用 catch 捕获,finally 确保输出"计算结束"。''
package demo
import std.env.*
import std.convert.*
main() {
try {
getStdOut().write("请输入第一个整数:")
let a = Int64.parse(getStdIn().readln().getOrThrow())
getStdOut().write("请输入第二个整数:")
let b = Int64.parse(getStdIn().readln().getOrThrow())
let result = a / b
println("${a} ÷ ${b} = ${result}")
} catch (e: ArithmeticException) {
println("错误: 除数不能为零")
} finally {
println("计算结束")
}
}
使用 try-with-resources 自动管理文件资源,写入 Hello, World! 到文件并自动关闭。
package demo
import std.fs.*
main() {
try (file = File.create("./src/hello.txt")) {
file.write("Hello, World!".toArray())
println("写入完成")
} catch (e: Exception) {
println("操作失败: ${e.message}")
} finally {
println("程序结束,文件资源已自动关闭")
}
}
findUser() 函数从用户名列表中查找用户,配合 getOrThrow() 强制取值并捕获异常。
package demo
func findUser(name: String): ?String {
let users = ["张三", "李四", "王五"]
for (u in users) {
if (u == name) {
return Some(u)
}
}
return None
}
main() {
try {
let u1 = findUser("李四").getOrThrow()
println("找到用户: ${u1}")
let u2 = findUser("赵六").getOrThrow()
println("找到用户: ${u2}")
} catch (e: NoneValueException) {
println("查找失败: 用户不存在")
}
}