跳到主要内容
版本:master

文件操作

1. 概述

文件操作是程序与外部存储系统交互的核心功能,用于实现数据的持久化存储与读取。GS 语言提供了一套全面且灵活的文件操作函数,支持文件的创建、读写、删除、属性管理等多种操作。本文档是 GS 文件操作的实用指南,主要内容包括:

  • 文件基础操作:文件的打开、关闭、读写与定位。
  • 文件信息管理:获取文件大小、状态信息、路径转换与时间戳修改。
  • 便捷文件函数:无需显式打开文件即可进行完整读写的高级函数。

阅读对象:已掌握 GS 标准 I/O 基础,需要学习文件系统交互的开发者。

阅读收获:快速掌握 GS 文件操作的核心 API,能够实现数据的持久化存储、配置文件读写、日志记录等关键功能。

2. 核心概念

在 GS 中,一个打开的文件被表示为一个 file 类型的句柄(handle)。文件操作遵循通用流程:

  1. 打开文件:使用 file.open函数,指定文件路径和模式(如只读 "r"、写入 "w"、追加 "a"),获取文件句柄。
  2. 进行操作:通过获得的文件句柄,调用读写、定位等方法。
  3. 关闭文件:操作完成后,调用句柄的 .close()方法以释放系统资源。

读写操作在失败时会返回整数错误码,读取操作在到达文件末尾(EOF)时返回 nil

3. 基础文件操作

3.1 文件的打开与关闭

使用 file.open函数并指定模式来打开文件,使用file.close函数关闭已打开的文件。

基本语法:

file file_instance = file.open(string file_name, string mode);

模式说明:

模式说明
"r"只读模式打开。文件必须存在。
"w"写入模式打开。文件存在则清空,不存在则创建。
"a"追加模式打开。文件存在则写入位置在末尾,不存在则创建。

简单示例:

// 以写入模式打开(或创建)文件
file fw = file.open("data1.txt", "w");
// ... 进行文件操作
fw.close(); // 操作完成后关闭文件

// 以追加模式打开文件
file fa = file.open("data2.txt", "a");
// ... 追加日志内容
fa.close();

示例3-1:简单的文件打开及关闭示例

​ 运行示例代码后,检查driver根路径,会发现原本不存在的data1.txtdata2.txt文件被创建出。尝试往data1.txt文件中添加随即内容后,再次运行代码,data1.txt文档中的内容会被清空。

3.2 写入文件

通过文件句柄的 write方法向文件写入内容,写入方法的content参数必须是string或者buffer类型的内容。

基本语法:

file_instance.write(string|buffer content)

示例如下:

file fw = file.open("greeting.txt", "w");
fw.write("Hello, ");
fw.write("World!\n");
fw.write("The answer is: ");
fw.write((string)42);
fw.write("\n");
fw.close();
// 文件内容为:
// Hello, World!
// The answer is: 42

示例3-2:文件写入示例

3.3 读取文件

通过文件句柄的 readgets方法从文件读取内容。read返回 buffer 类型,gets返回字符串类型。

基本语法:

file_instance.read(int n, bool line_mode = false);
  • 从文件中读取指定字数内容,允许开启按行读取模式。
  • 返回值:
    • 读取错误时返回 int 错误码。
    • 在文件结尾时返回 nil。
    • 正确读取时返回 buffer 类型的文件内容。
file_instance.gets(int n = 65535)
  • 从文件中读取一行字符。
  • 返回值:
    • 读取错误时返回 int 错误码。
    • 在文件结尾时返回 nil。
    • 正确读取时返回 string 类型的文件内容。

文件读取示例如下:

// 写入示例内容
file fw = file.open("sample.txt", "w");
fw.write("First Line\nSecond Line\nThird Line\nFourth line");
fw.close();

// 读取文件
file fr = file.open("sample.txt", "r");

// 使用 gets 读取一行(最多65535字符)
string first_line = fr.gets();
printf("First line: %s", first_line); // 注意:gets 可能包含换行符

// 使用 read 读取指定字节数到 buffer
mixed data = fr.read(6); // 读取 "Second"
if (is_buffer(data))
write("Read buffer data: ", data);

// 读取本行剩余的内容, " Line"
string rest_line_content = fr.gets(65535);
write("Rest line content: ", rest_line_content);

// 以行阅读模式读取下一行内容
buffer rest_content = fr.read(65535, true);
write("Rest content: ", rest_content);
fr.close();

示例3-3:文件读取示例

3.4 文件定位

使用 seek方法移动文件内部指针,使用 tell方法查询当前指针位置。

简单示例如下:

file fr = file.open("data.txt", "rw");

// 获取当前位置(初始为0)
int pos = fr.tell();
printf("Current position: %d\n", pos); // 输出: Current position: 0

// 跳过前10个字节
fr.seek(10, SeekOrigin.BEGIN);

// 再次获取位置
pos = fr.tell();
printf("Position after seeking 10 bytes: %d\n", pos); // 输出: 10

// 从当前位置回退5字节
fr.seek(-5, SeekOrigin.CURRENT);
pos = fr.tell();
printf("Position after seeking -5 from current: %d\n", pos); // 输出: 5

fr.close();

示例3-4:文件定位示例

4. 文件信息与管理

4.1 获取文件大小

使用 file.size函数或文件句柄的 .size()方法获取文件大小(字节数)。

简单示例:

string filename = "my_file.dat";

// 方法1:直接通过路径获取
int file_size = file.size(filename); // 文件不存在时返回 -1
printf("Size of '%s': %d bytes\n", filename, file_size);

// 方法2:通过已打开的文件句柄获取
file f = file.open(filename, "rw");
int size_via_handle = f.size(); // 以 "rw" 模式打开后文件存在,文件为空,文件大小为0
printf("Size via handle: %d bytes\n", size_via_handle);
f.close();

示例4-1:获取文件大小

4.2 获取文件状态

使用 file.stat函数或文件句柄的 .stat()方法获取文件的详细信息。

示例如下:

file.open("example.txt", "rw"); // 以"rw"模式打开以创建 example.txt 文件
mixed info = file.stat("example.txt");
if (is_map(info))
{
printf("File Path: %s\n", info["path"]);
printf("Size: %d bytes\n", info["size"]);
printf("Is Directory: %s\n", info["is_dir"] ? "true" : "false");
// 可以转换时间戳为可读格式
printf("Modification Time: %s", time.ctime(info["time"]));
}

示例4-2:获取文件状态

4.3删除与重命名

通过file.reaname重命名文件,file.delete删除文件。

// 创建一个临时文件
file f = file.open("temp.txt", "w");
f.write("Temporary data");
f.close();

// 重命名文件
bool rename_ok = file.rename("temp.txt", "permanent.txt");
if (rename_ok)
writeln("File renamed successfully.");
else
writeln("Rename failed.");

// 删除文件
bool delete_ok = file.delete("permanent.txt");
if (delete_ok)
writeln("File deleted successfully.");
else
writeln("Delete failed. File may not exist.");

5. 便携函数

5.1 一次性读写整个文件

file.read_all/file.write_all这些函数无需手动打开和关闭文件,简化了完整文件的读写操作。

简单示例:

string content = "This is the entire file content.\nLine 2.\nLine 3.";

// 一次性写入整个文件
file.write_all("complete.txt", content);

// 一次性读取整个文件
mixed full_content_buffer = file.read_all("complete.txt", "b"); // "b" 表示以二进制模式读取
writeln("Full file content (as buffer):");
writeln(full_content_buffer);

// 也可以读取为字符串(如果内容是文本)
// 通常需要根据 buffer 内容进行解码,这里简单示例直接输出

示例5-1:整体读写示例

5.2 追加内容与记录日志

file.append 在文件末尾追加内容,file.log记录格式化日志,示例如下:

// 使用 file.append 追加内容(无需打开模式为 "a")
file.append("journal.txt", "Event 1: System started.\n");
file.append("journal.txt", "Event 2: User logged in.\n");

// 使用 file.log 记录格式化日志输出至`app.log`文件中
file.log("app.log", "User %s performed action %s.", "Alice", "login");
// 日志文件会包含格式化的行,如: [Timestamp] User Alice performed action login.

示例5-2:追加文件内容与记录日志

6 综合示例

以下示例演示了完整的文件操作流程:创建文件、写入数据、读取并处理数据、获取文件信息。

import gs.lang.string;
// 1. 创建并写入数据
file fw = file.open("products.dat", "w");
fw.write("ProductA,25.99,50\n");
fw.write("ProductB,15.50,30\n");
fw.write("ProductC,40.00,10\n");
fw.close();

// 2. 读取并处理数据
file fr = file.open("products.dat", "r");
float total_value = 0.0;
mixed line;
while ((line = fr.gets()) != nil)
{
// 移除行尾换行符并分割字符串
line = line.remove_tail("\r\n");
array parts = line.explode(",");
if (parts.length() == 3)
{
string name = parts[0];
float price = float.parse(parts[1]);
int quantity = int.parse(parts[2]);
float item_value = price * quantity;
total_value += item_value;
printf("Product: %s, Stock Value: $%.2f\n", name, item_value);
}
}

fr.close();
printf("Total inventory value: $%.2f\n", total_value);

// 3. 获取文件信息
mixed file_info = file.stat("products.dat");
printf("File '%s' size: %d bytes, modified at: %s",
file_info["path"], file_info["size"], time.ctime(file_info["time"]));
// 4. 清理(可选)
// file.delete("products.dat");

示例5-3:综合文件操作示例

7. 拓展阅读

更多相关内容请参阅如下文档:

8 总结

本文档详细介绍了 GS 语言中文件操作的核心功能。关键要点包括:

  1. 核心流程:文件操作遵循 打开 -> 操作 -> 关闭 的标准流程,使用 file.open.close()管理文件句柄的生命周期。
  2. 基础读写:通过文件句柄的 writereadgets方法可以进行灵活的数据写入与读取,并使用 seektell进行精确定位。
  3. 文件管理:使用 file.sizefile.stat获取文件属性,使用 file.deletefile.rename管理文件本身。
  4. 高效工具函数file.read_allfile.write_allfile.append等函数为常见场景提供了无需手动管理文件句柄的便捷方式,简化了代码。

通过掌握这些知识,开发者已经能够胜任 GS 应用中大部分的文件交互任务,为开发数据持久化、配置管理、日志系统等功能奠定了坚实基础。建议结合具体项目需求,多加练习以熟练掌握。