【问题标题】:How can i read the same file two times in Java?如何在 Java 中读取同一个文件两次?
【发布时间】:2016-03-09 06:39:18
【问题描述】:

我想对文件的行进行反击,在第二遍中,我想获取每一行并对其进行操作。它没有编译错误,但不能进入第二个 while ((line = br.readLine()) != null) 。 有没有不同的方法来获取文件的行(电影)并存储在数组中?

        BufferedReader br = null;

        try { // try to read the file
            br = new BufferedReader(new FileReader("movies.txt"));
            String line;
            int numberOfMovies = 0;
            while ((line = br.readLine()) != null) {
                numberOfMovies++;
            }
            Movie[] movies = new Movie[numberOfMovies]; // store in a Movie
                                                        // array every movie of
                                                        // the file
            String title = "";
            int id = 0;
            int likes = 0;
            int icounter = 0; // count to create new movie for each line
            while ((line = br.readLine()) != null) {
                line = line.trim();
                line = line.replaceAll("/t", "");
                line = line.toLowerCase();
                String[] tokens = line.split(" "); // store every token in a
                                                    // string array
                id = Integer.parseInt(tokens[0]);
                likes = Integer.parseInt(tokens[tokens.length]);
                for (int i = 1; i < tokens.length; i++) {
                    title = title + " " + tokens[i];
                }
                movies[icounter] = new Movie(id, title, likes);
                icounter++;
            }


        } catch (IOException e) {
            e.printStackTrace();
        }

【问题讨论】:

  • 你真的读过两次文件吗?如果您知道文件可以放入内存中,您可以只读取一次并将其存储在内存中,然后从那里再次读取

标签: java file bufferedreader java-io


【解决方案1】:

这是本文中已有的几个其他答案的组合,但这是我将如何重写代码以填充列表的方式。这双重解决了以下问题:1) 需要两次读取文件 2) 使用 BufferedReader 删除样板文件,同时使用 Java8 Streams 使 List 的初始化尽可能简洁:

private static class Movie {
    private Movie(int id, String title, int likes) {
        //TODO: set your instance state here
    }
}

private static Movie movieFromFileLine(String line) {
    line = line.trim();
    line = line.replaceAll("/t", "");
    line = line.toLowerCase();
    String[] tokens = line.split(" "); // store every token in a

    String title = "";
    int id = Integer.parseInt(tokens[0]);
    int likes = Integer.parseInt(tokens[tokens.length]);
    for (int i = 1; i < tokens.length; i++) {
        title = title + " " + tokens[i];
    }
    return new Movie(id, title, likes);
}

public static void main(String[] args) throws IOException {
    List<Movie> movies = Files.readAllLines(Paths.get("movies.txt"), Charset.defaultCharset()).stream().map
            (App::movieFromFileLine).collect(Collectors.toList());
    //TODO: Make some magic with your list of Movies
}

如果您绝对需要读取源(文件、URL 或其他)两次,那么您需要注意内容很可能在第一次和第二次读取之间发生变化,并准备好处理那些差异。

如果您可以合理假设源的内容将适合内存并且您的代码完全期望在多个 Readers/InputStreams 实例上工作,您可以首先考虑使用来自 @987654321 的适当 IOUtils.copy 方法@ 读取源的内容并将其复制到 ByteArrayOutputStream 以创建可以一遍又一遍地重新读取的 byte[]。

【讨论】:

    【解决方案2】:

    首先,不需要两次读取文件。

    其次,为什么不使用java.nio.file.Files 类来读取文件。

    它有一个方法readAllLines(Path path, Charset cs) 可以返回一个List&lt;String&gt;

    那么如果你想知道有多少行,只需调用列表中的size()方法,就可以使用列表构造Movie对象。

    List<Movie> movieList = new ArrayList<>();
    
    for (String line : Files.readAllLines(Paths.get("movies.txt"), Charset.defaultCharset())) {
    
         // Construct your Movie object from each individual line and add to the list of Movies
    
         movieList.add(new Movie(id, title, likes));
    }
    

    Files 类的使用还减少了您的样板代码,因为它会在完成读取后处理关闭资源,这意味着您不需要 finally 块来关闭任何内容。

    【讨论】:

      【解决方案3】:

      最简单的方法是再次重置br

      try { // try to read the file 
          br = new BufferedReader(new FileReader("movies.txt"));
          String line; int numberOfMovies = 0;
          while (br.hasNextLine()){
              numberOfMovies++;
          }
          br.close();
          Movie[] movies = new Movie[numberOfMovies];
          // store in a Movie
          // array every movie of
          // the file
          String title = "";
          int id = 0;
          int likes = 0;
          int icounter = 0;
          // count to create new movie for each line
          br = new BufferedReader(new FileReader("movies.txt"));
          while ((br.hasNextLine()) {
              line = line.trim();
              line = line.replaceAll("/t", "");
              line = line.toLowerCase();
              String[] tokens = line.split(" ");
              // store every token in a
              // string array
              id = Integer.parseInt(tokens[0]);
              likes = Integer.parseInt(tokens[tokens.length]);
              for (int i = 1; i < tokens.length; i++) {
                  title = title + " " + tokens[i];
              }
              movies[icounter] = new Movie(id, title, likes);
              icounter++;
          }
      } catch (IOException e) { e.printStackTrace(); }
      

      我将br.nextLine() != null 更改为br.hasNextLine(),因为在这种情况下它更短更合适。而且它不会消耗一条线。

      【讨论】:

        【解决方案4】:

        您正在使用BufferedReader 运行文件,直到下一行指向null。由于您的BufferedReadernull,它甚至不会输入第二个while((line = br.readline) != null),因为第一个读取行是null

        尝试获取新的 BufferedReader。像这样:

        ...
        int id = 0;
        int likes = 0;
        int icounter = 0;
        br = new BufferedReader(new FileReader("movies.txt")) //Re-initialize the br to point 
                                                              //onto the first line again
        while ((line = br.readLine()) != null)
        ...
        

        编辑: 先关闭阅读器..

        【讨论】:

          【解决方案5】:

          如果您使用相同的 Reader,则在您到达第二个循环时,所有内容都已被读取。

          关闭第一个阅读器,然后创建另一个阅读器进行第二次阅读。

          【讨论】:

          • 我该怎么做?只创建一个新的 BufferedReader ?
          • 是的,只要再写这行:br = new BufferedReader(new FileReader("movies.txt"));看看biziclop的回答,不错。
          【解决方案6】:

          这里有两件事:

          1. InputStreams 和 Readers 是一次性结构:一旦你读到最后,你要么需要explicitly rewind它们(如果它们支持倒带),或者你需要关闭它们(始终关闭您的信息流和阅读器!)并打开一个新的。

          2. 但是,在这种情况下,这两个通道完全没有必要,只需使用动态增长的结构来收集您的 Movie 对象而不是数组:例如 ArrayList

          【讨论】:

            猜你喜欢
            • 2013-12-28
            • 1970-01-01
            • 2012-12-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-10-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多