运行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
相关产品推荐
相关产品推荐

