You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

运行ml-lex后如何通过makeLexer函数读取文件输入?

解决ML-Lex中Too many open files异常的问题

你的问题根源在于每次调用lexer时都会重复打开同一个文件,导致系统文件句柄被耗尽。让我一步步帮你修正这个问题:

问题分析

你写的代码:

val lexer = makeLexer(fn n => valOf(inputLine(openIn("test.txt"))));

这里的匿名函数fn n => ...会在lexer()每次需要读取输入时被调用。而每次调用都会执行openIn("test.txt"),打开一个全新的文件句柄。系统对单个进程能打开的文件数量有上限,多次调用后就触发了Io异常。

正确的实现方式

我们需要提前打开一次文件,复用同一个文件句柄,而不是每次读取都重新打开:

1. 先打开文件并保存句柄

首先打开目标文件,把文件句柄存到一个变量里,后续所有读取操作都用这个句柄:

open TextIO;
val infile = openIn("test.txt");

2. 创建复用句柄的Lexer

将这个已打开的句柄传入makeLexer的读取函数,每次读取都用它来获取输入:

val lexer = makeLexer (fn n => 
    case inputLine(infile) of
        SOME line => line  (* 读取到一行内容,返回给lexer *)
      | NONE => ""         (* 遇到文件末尾,返回空字符串让lexer处理EOF *)
);

这里用case代替valOf是为了避免inputLine返回NONE(文件结束)时抛出异常,让代码更健壮。

3. 处理Token并关闭文件

处理完所有Token后,一定要关闭文件句柄,避免资源泄漏:

(* 假设你的lexer定义了Token类型,其中包含EOF标记 *)
fun processTokens () =
    case lexer() of
        Token.EOF => (closeIn(infile); print "Token processing completed.\n")
      | token => (print (Token.toString token ^ "\n"); processTokens());

(* 启动处理流程 *)
processTokens();

额外注意事项

  • 如果你需要重新读取文件,要先调用closeIn(infile)关闭旧句柄,再重新执行openIn。
  • 不要在读取函数里重复打开文件,这不仅会导致句柄耗尽,还会每次都从文件开头读取,逻辑上也不符合预期。
  • 始终记得关闭打开的文件句柄,长期不关闭会造成系统资源浪费。

内容的提问来源于stack exchange,提问作者sahilbansal17

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:34:08