根本原因是scanner默认以空格和换行符为分隔符,遇空行或末尾换行易耗尽输入流;用next()前未校验hasnext()会抛nosuchelementexception;推荐hasnextline()+nextline()逐行读,注意nextint()后需额外nextline()清除换行符,并显式指定utf-8编码。

Scanner读文件时卡住或抛NoSuchElementException
根本原因不是文件没找到,而是Scanner默认用空格/换行作分隔符,遇到空行、末尾换行或纯空白字符就可能提前耗尽输入流。尤其当用next()或nextInt()这类“跳过分隔符”的方法时,hasNext()返回false后还强行调用next(),立刻崩出NoSuchElementException。
- 优先用
hasNextLine()+nextLine()逐行读,不依赖内容格式 - 避免混用
nextXXX()和nextLine():比如刚调完nextInt(),下一行nextLine()会读到残留的换行符,直接返回空字符串——此时得额外加一次nextLine()“吃掉”它 - 文件编码必须匹配:中文乱码大概率是没指定
Charset,构造Scanner时显式传StandardCharsets.UTF_8
Scanner vs BufferedReader读文件性能差多少
Scanner本质是带词法解析的包装器,每次nextXXX()都要做正则匹配、类型转换、异常捕获;而BufferedReader只是高效搬运字符。小文件(Scanner慢2–5倍很常见。
- 纯按行处理(如解析配置、日志过滤):直接上
BufferedReader,代码更短、更稳 - 真需要切分字段(如
"name,age,city"):先用BufferedReader.readLine()拿整行,再用String.split(",")或StringTokenizer——比Scanner.useDelimiter(",")快且可控 -
Scanner唯一优势场景:交互式命令行输入,或格式高度不规则需边读边判断类型
用Scanner读文件必须关流吗
必须。虽然Scanner的close()会级联关闭底层FileInputStream,但漏掉它会导致文件句柄泄露——Windows下文件可能被锁死,Linux下累积太多会触发“Too many open files”错误。
- 别用
finally手动关:容易在catch里重复关或吞异常 - 一律用try-with-resources:
try (Scanner sc = new Scanner(new File("data.txt"), StandardCharsets.UTF_8)) { ... } - 注意:如果传入的是
System.in,千万别关——关了整个控制台输入就废了
Scanner读取路径含中文或空格的文件失败
不是Scanner的问题,是File或Path构造时没转义。直接拼接"C:data测试.txt"在Windows下会因反斜杠被当转义符而路径错乱;空格则让File误判为多个参数。
立即学习“Java免费学习笔记(深入)”;
- 路径统一用
Paths.get("C:/data/测试.txt")或new File("C:\data\测试.txt")(双反斜杠) - 更稳妥:用
getClass().getResource("/data/test.txt")从classpath读,避免绝对路径问题 - 运行时报
FileNotFoundException?先用new File("xxx").exists()打个断点确认路径是否真存在










