【问题标题】:infinite loop occurs when trying to read a file with FileReader object尝试使用 FileReader 对象读取文件时发生无限循环
【发布时间】:2015-09-13 13:36:36
【问题描述】:

我尝试使用 FileReader 从文件中读取,但程序进入无限循环:这是我的代码:

import java.io.FileReader;

public class Test {
    public static void main(String[] args)  {
        try(FileReader f = new FileReader("sales.dat");){
            char ch = (char)f.read();
            while(ch != -1){
                ch = (char)f.read();
                System.out.print(ch);
            }
        }catch (Exception e){
        }
    }
}

为什么只使用 FileReader 读取文件效率不高,最好使用 BufferedReader 对象

【问题讨论】:

  • 您将 read() 值转换为 char,然后将该 char 与 int 进行比较...没有“负字符”之类的东西...
  • @Marc B 将此添加为答案。
  • @MarcB 谢谢我修好了

标签: java


【解决方案1】:

char 的范围在065535 之间,所以它不能是-1,所以char != -1 始终为真。

while(int ch; (ch = f.read()) >= 0;)
   System.out.print((char) ch);

这将在转换为 char 之前检查该值是否为非负数

为什么只使用 FileReader 读取文件效率不高,最好使用 BufferedReader 对象

BufferedReader 使用 FileReader 所以也许问题应该是;为什么不单独使用 FileReader?

答案是;调用操作系统很昂贵。每次调用可以是几微秒,而进程内存访问可以是纳秒。

通过使用缓冲区,例如使用 BufferedReader,您调用操作系统的次数要少得多(默认情况下最多为 1/8192),这提高了获取每个数据字节的效率。

在上面的例子中,它几乎不重要。虽然调用 FileReader 很昂贵,但与写入控制台相比它更便宜。就性能而言,写入控制台是唯一重要的事情。

【讨论】:

    【解决方案2】:

    相反,您可以像这样按行读取

    final File file = new File("your_file");
    try (final InputStream fileStream = new FileInputStream(file.getAbsolutePath()); final Reader decoder = new InputStreamReader(fileStream);
            final BufferedReader buffered = new BufferedReader(decoder)) {
        String line;
        while ((line = buffered.readLine()) != null) {
            // do stuff
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    

    ps。不知道你的子问题

    【讨论】:

    • 您需要从某个地方开始,我使用此代码进行所有阅读... BufferedReader(和其他东西)的好处是您可以给它一个 zipStream 或任何相关的流...
    【解决方案3】:

    你不能得到一个负的 char 值,所以小于 -1 的检查总是假的。

    当使用子类InputStreamReader 时,您应该依靠ready() 来检查您是否已到达流的末尾。

    while(reader.ready()){
        // do stuff
    }
    

    使用缓冲流更快,因为它减少了 OS IO 调用的数量。如果您有一个包含 100 万字节的文件并且一次读取一个字节,那么对于每个非缓冲调用,JVM 都需要从操作系统请求读取。这是 Java 进程请求从操作系统读取的 100 万次。对于缓冲流,它会尝试在一次读取中填充其缓冲区。因此,即使您请求 1 个字节,底层流在内存中也会有 N 个字节,从而将底层操作系统的调用次数减少了大约 FILE_SIZE/BUFFER_SIZE。对于 1 MB 的文件,如果缓冲区大小为 1024,并且每次都能填满,那么 OS 调用的数量将为 1M/1K,即 1000 次读取对 100 万次。

    【讨论】:

    • 解释得很好,非常感谢,我完全不明白为什么 BufferedReader 使用起来很有效
    • @KhatabBouchra 不客气。如果答案对您有所帮助,通常习惯性地对其进行投票。
    • 我很想给它投票,但我没有足够的声望点来投票,所以一旦我达到这些点,我就会投票给它:)
    猜你喜欢
    • 2012-10-27
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 2013-08-07
    • 2020-02-07
    • 1970-01-01
    相关资源
    最近更新 更多