scanner读文件应避免new scanner(new file(...)),需显式指定编码并用try-with-resources;next()跳过分隔符含换行,nextline()按行读且受前序操作影响;自定义正则分隔符时skip()行为变化,避免空匹配;hasnextxxx()有预读副作用,建议先next()再解析;性能敏感场景优先用bufferedreader或split。

Scanner 能读文件但别直接 new Scanner(new File(...))
Java 的 Scanner 确实能读文件、字符串、字节数组甚至网络流,但最常踩的坑是用错构造函数导致中文乱码或资源泄漏。直接传 File 对象会默认用系统编码(Windows 是 GBK),读 UTF-8 文件大概率崩。
- 用
new Scanner(new FileInputStream("a.txt"), "UTF-8")显式指定编码 - 更稳妥的是先转成
Path+Files.newInputStream():new Scanner(Files.newInputStream(Paths.get("a.txt")), "UTF-8") - 记得在 try-with-resources 里用,
Scanner实现了AutoCloseable,不关可能锁住文件
parseString 时 next() 和 nextLine() 的行为差异
从字符串创建 Scanner(如 new Scanner("a b
c"))后,next() 和 nextLine() 的换行处理逻辑完全不同——这不是 bug,是设计如此:前者跳过所有分隔符(含换行),后者只吃掉当前行末尾的换行符,且会把前一次调用留下的换行当成空行返回。
-
next()基于分隔符(默认空白字符)切词,遇到换行就当普通空白,继续读下一行的词 -
nextLine()是按行吞,但会“吃掉”分隔符后的换行符;如果前一个操作是nextInt(),它没吃掉换行,nextLine()就立刻返回空字符串 - 解析带空行的配置文本时,优先用
hasNextLine()+nextLine(),再手动trim().isEmpty()判断是否跳过
正则分隔符设错会导致 skip() 不生效或死循环
Scanner 默认用 p{javaWhitespace}+ 当分隔符,但一旦调用 useDelimiter() 改成自定义正则(比如 "s*,s*"),skip() 方法的行为就变了:它只跳过**匹配整个分隔符模式**的前缀,不是跳过任意分隔符片段。
- 写
useDelimiter("\s*,\s*|\s+")这种“或”逻辑容易漏掉边界情况,建议拆成两步:先skip("\s*")再用next() - 如果分隔符正则能匹配空字符串(比如
"*"或"?"),Scanner会卡住,抛IllegalStateException - 调试时打印
scanner.delimiter()看实际生效的 Pattern,比猜靠谱
用 Scanner 解析日志行要小心 hasNextXXX() 的预读副作用
hasNextInt()、hasNextDouble() 这类方法会预读输入并回退,但回退位置不精确——尤其在自定义分隔符下,可能把本该属于下个 token 的字符吞掉,导致后续 next() 返回异常内容。
- 不要混用
hasNextXXX()和next()做类型试探,改用next()拿字符串再Integer.parseInt()更可控 - 日志行格式固定时(如
"2024-01-01 INFO user=abc"),用useDelimiter("\s+")+next()拆字段,比反复试探快且稳定 - 性能敏感场景避免
Scanner,它内部有大量正则匹配和缓冲区拷贝,String.split()或BufferedReader.readLine()+ 手动切更轻量
真正麻烦的是混合分隔符和不定长字段,比如 CSV 里带引号的逗号。这时候 Scanner 的 delimiter 机制根本不够用,得换 OpenCSV 或自己写状态机。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











