跳到主要内容
版本:master

标准IO

1. 概述

​ 标准输入输出(Standard I/O)是程序与用户交互的基石,负责处理键盘输入、屏幕信息显示等内容。GS 提供了一套功能完善的 I/O 函数,用于构建交互式应用。

本文档是 GS 标准 I/O 的实用指南,主要内容包括:

  • 基础输出:格式化输出 (printf) 与直接输出 (write)
  • 基础输入:读取用户输入 (input_string)
  • 广播消息:多终端消息通知 (broadcast)

阅读对象:GS 初学者和需要快速查阅标准IO相关内容的的开发者。

阅读收获:快速掌握核心 I/O 函数的使用,能够实现用户交互、数据展示等关键功能。

2. 概念

什么是标准输入输出?

标准I/O是操作系统为每个程序预定义的三个标准数据流,它们构成了程序与外界(通常是终端或控制台)通信的基本通道:

  • 标准输入:程序接收信息的数据流。默认指向键盘输入。当程序需要读取用户指令或数据时,就从这个流中读取。
  • 标准输出:程序正常输出信息的数据流。默认指向屏幕或终端显示。程序运行的结果、提示信息等通过此流输出。
  • 标准错误:程序输出错误信息或警告的特殊数据流。默认也指向屏幕,但独立于标准输出。这使得错误信息可以被单独过滤或重定向,而不会与正常输出信息混淆。

3. 标准输出

3.1 printf - 格式化输出

printf 函数类似于C语言中的格式化输出,根据格式化字符串对参数进行格式化输出。

基本语法:

printf("格式化字符串", 参数1, 参数2, ...);

简单示例:

//# 基本字符串格式化
printf("Welcome to %s!\n", "GS");
//# 整数格式化
printf("Decimal: %d, Octal: %o, Hexadecimal: %x\n", 255, 255, 255);
//# 浮点数格式化
printf("Floating-point number: %.2f\n", 3.14159);
//# 对象格式化
printf("Output object is: %O\n", this_object());
//# 数组格式化输出(详细格式)
array data = [1, "hello", 3.14, ["nested", "array"]];
printf("Verbose format: %O\n", data);
//# 数组格式化输出(紧凑格式)
printf("Compact format: %M\n", data);
// Compact format: [1,"hello",3.14,["nested","array"]]

示例3-1:printf 使用示例

常用格式化符号:

符号说明示例
%s字符串printf("%s", "hello")
%d整数printf("%d", 123)
%f浮点数printf("%f", 3.14159)
%O详细格式printf("%O", [1,2,3])
%M紧凑格式printf("%M", [1,2,3])

3.2 write - 简单输出

write 函数更简单,不需要格式化字符串,直接输出内容。

基本语法:

write(1,2,3, ...);

简单示例:

//输出字符串
write("Hello\n"); //'\n' 为换行换行
writeln("Hi"); //等效于 write("Hi\n")
//Hello

//输出多个值(自动用空格分隔)
write(3, "apples\n");
//3 apples

//输出数字和数组
write("number: ", 123, ", array: ", [1,2,3],"\n");
//number: 123, array: [1,2,3]

//换行输出
write("first line");
write("\n"); //换行
write("second line");
//第一行
//第二行

示例3-2:write 使用示例

printf vs write 对比:

// printf vs write 对比:
//相同效果的两种写法
printf("name:%s, age:%d\n", "lisi", 25);
//name:lisi,age:25

write("name:", "lisi", ",age:", 25, "\n");
//name: lisi ,age: 25

3.3 错误输出

​ 在之前的异常处理章节中,我们已经了解到 GS 的报错及异常处理机制。需要注意的是GS的报错输出除了像标准输出一样在控制台输出信息外,还有有一个重要区别:

错误输出的特殊处理

  • 所有通过错误输出的内容不仅会显示在控制台。
  • 同时会自动写入到默认的 log.txt日志文件中。
  • 这为错误追踪和调试提供了便利的持久化记录。

使用示例:

try
{
// 清空日志文件
file.write_all("./log.txt", "");
// 报错
error("Try write to error log");
}
catch
{
// 读取报错后日志文件内容
string log_file_content = file.read_all("./log.txt");
writeln("\nGet file content: \n", log_file_content);
}

示例3-3:错误输出示例

示例运行结果如下:

Error(-1): Try write to error log
Coroutine: co[440664:v0]boot
Domain: domain[2048:v0]zero [local call]
At /test.gs:6 (::entry) in object[2881105:v0]/test.gs
At <Internal routine>

Get file content:
Fri Oct 17 14:12:46 2025 [INTERNAL] Error(-1): Try write to error log
Coroutine: co[440664:v0]boot
Domain: domain[2048:v0]zero [local call]
At /test.gs:6 (::entry) in object[2881105:v0]/test.gs
At <Internal routine>

​ 从示例的输出结果可以看到,日志文件中完整保留了报错信息内容的同时,在报错信息前添加有时间戳Fri Oct 17 14:12:46 2025方便确定问题的发生时间,以及[INTERNAL]标记用于区分GS内部宝座与其他自订的日志输出。

4. 标准输入

4.1 input_string - 读取用户输入

input_string 让程序能够读取用户从键盘输入的内容。需要注意的是input_string定义在内置脚本文件/gs/lang/io.gs中,使用前需要import gs.lang.io;导入内置脚本文件。

基本语法:

string 变量名 = input_string("提示信息");

简单示例:

//基本输入
import gs.lang.io;
import gs.lang.string; // 用与导入移除尾字符串的 remove_tail 函数

string name = input_string("Please input your name:");
//please input your name: jszx
printf("Hello, %s!\n", name);
//Hello, jszx
//!
//输入的回车符号被保留了,移除它
printf("Afer remove tail, reuslt is %s!\n", name.remove_tail("\r\n"));
//Afer remove tail, reuslt is jszx!

//数字输入(需要转换)
string age_input = input_string("Please input your age:");
// Please input your age:18
int age = int.parse(age_input); //字符串转整数
printf("You will be %d years old next year\n", age + 1);
//You will be %d years old next year

//密码输入(不显示输入内容)
string password = input_string("Please input password:");
// Please input password:******
printf("Password length: %d characters\n", password.length());
// Password length: 8 characters

示例4-1:基础输入示例

​ 需要注意的是input_string作为输入会将输入的\r\n回车符号保留,如不需要可调用内置脚本/gs/lang/string.gs中定义的string.remove_tail(string suffix)函数移除。

输入验证示例:

import gs.lang.io;
int get_number_input(string prompt)
{
while (true)
{
string input = input_string(prompt);
int number = int.parse(input);
if (number == 0 && input != "0\r\n")
printf("Error: Please input valid score!\n");
else
return number;
}
}

int score = get_number_input("Please input score:");
// Please input score:abc
// error:please input valid score!
// Please input score:95
printf("Score:%d\n", score);
// Score: 95

示例4-2:简单的输入验证示例

5. 特殊输出

5.1 broadcast - 广播消息

broadcast 向所有 cosole device广播格式化消息。格式化方式与printf相同,仅输出设备存在不同。

基本语法:

broadcast("格式化字符串", 参数1, 参数2, ...);

简单示例:

一般来讲,要体现broadcast的广播特点,我们至少需要创建一个telnet服务,一个telnet客户端。运行如下示例代码:

import gs.telnetd;
load_static(telnetd, this_domain());

示例5-1:创建一个telnet服务

示例会创建一个在默认端口2099的 telnet 服务,默认密码为ask。此时我们打开windows的命令行工具执行以下命令:

telnet 127.0.0.1 2099

输入默认密码后即可进入 telnet 客户端。在服务端或客户端输入如下代码:

broadcast("Try broadcast");

我们发现两个 cosole device 的窗口均有Try broadcast消息输出。而通过printf输出的内容则只在当前窗口输出。

拓展阅读

更多标准输入输出相关内容,请查阅:

总结

​ 本文档系统介绍了GS语言的标准输入输出功能,涵盖了标准输入(接收数据)、标准输出(正常信息输出)和标准错误(错误信息输出)三大标准数据流的核心概念。通过详细的示例和对比,重点讲解了格式化输出 (printf)、简单输出 (write/writeln)、用户输入 (input_string) 和广播消息 (broadcast) 等关键函数的使用方法与适用场景。

核心要点回顾

  1. 标准输出:掌握了使用 printf进行复杂的格式化输出,能够精确控制字符串、整数、浮点数及对象(%O详细格式、%M紧凑格式)的显示形式;同时也学会了使用更简洁的 writewriteln进行快速、直接的输出。
  2. 标准输入:理解了通过 input_string读取用户输入的基本流程,并学习了处理输入尾部回车符、进行字符串到整数等数据类型转换以及实现简单的输入验证等重要技巧。
  3. 错误输出:明确了系统错误和异常信息不仅会输出到控制台,还会自动持久化记录到日志文件(如 log.txt)的机制,这对于程序调试和问题追踪至关重要。
  4. 特殊输出:认识了 broadcast函数在多终端环境(如 Telnet 服务)下向所有连接设备广播消息的独特用途,与 printf的单一控制台输出形成对比。

​ 标准 I/O 是构建交互式应用的基石,熟练掌握本文档内容,将能够有效实现程序与用户的数据交互和信息展示。这为后续学习文件操作、网络通信等更高级的主题奠定了坚实的基础。建议开发者结合文档中的示例进行实践练习,以深化理解并灵活运用