如何使用Java方法在循环中逐行处理输入文件?

时间:2018-11-27 06:25:23

标签: java for-loop methods

我正在使用Java通过在循环中为输入的每一行调用多种方法来处理文件。问题在于方法在循环的每次迭代中仅读取输入的第一行。例如,此输入:

Jones 90 90 90
Brown 80 80 80
Smith 70 70 70

应导致输出:

Jones 90 A
Brown 80 B
Smith 70 C

但是我最终得到了:

Jones 90 A
Brown 90 A
Smith 90 A

是否可以在下面的代码中使用studentAveragedetermineGrade方法来处理输入的第二行和第三行,如上例所示,还是我需要重新考虑整个循环/方法结构?

import java.io.*;
import java.util.Scanner;

public class Lab07Part01
{
    public static void main(String[] args) throws IOException
    {
        File infile = new File("Grades.txt");
        Scanner myfile = new Scanner(infile);
        Scanner counter = new Scanner(infile);

        String studentName = "";
        int testQty = 0;
        int studentQty = -1;
        double studentAvg = 0.0;
        double classSum = 0.0;
        double classAvg = 0.0;
        char letterGrade = 'X';

        while(counter.hasNextLine()) {
            studentQty++;
            counter.nextLine();
        }

        testQty = myfile.nextInt();

        System.out.println("Name   Average   Letter Grade");
        for(int i = 0; i < studentQty; i++) {
            studentName = myfile.next();
            studentAvg = studentAverage(testQty);
            classAvg += studentAvg;
            letterGrade = determineGrade(studentAvg);
            System.out.println(studentName + " " + studentAvg + " " + letterGrade);
            myfile.nextLine();
        }

        classAvg = overallAverage(studentQty, classSum);

        System.out.println("The average test grade is: " + classAvg);

    }

    public static double studentAverage(int testQty) throws IOException
    {
        File infile = new File("Grades.txt");
        Scanner scanavg = new Scanner(infile);
        double studentSum = 0;

        scanavg.nextLine();
        scanavg.next();

        for(int i = 1; i <= testQty; i++) {
            studentSum += scanavg.nextDouble();
        }

        double studentAvg = studentSum / testQty;
        return studentAvg;
    }

    public static char determineGrade(double studentAvg) throws IOException
    {
        char letterGrade = 'X';

        if(studentAvg >= 90.0)
            letterGrade = 'A';
        else if(studentAvg >= 80.0)
            letterGrade = 'B';
        else if(studentAvg >= 70.0)
            letterGrade = 'C';
        else if(studentAvg >= 60.0)
            letterGrade = 'D';
        else if(studentAvg < 60.0)
            letterGrade = 'F';

        return letterGrade;
    }

    public static double overallAverage(int studentQty, double classSum) throws IOException
    {
        double classAvg = classSum / studentQty;
        return classSum;
    }
}

3 个答案:

答案 0 :(得分:1)

我会一次读取整行来使用扫描仪。然后,我们可以在一个逻辑步骤中处理整行:

File infile = new File("Grades.txt");
Scanner myfile = new Scanner(infile);

while (myfile.hasNextLine()) {
    String line = myfile.nextLine();
    String[] parts = line.split("\\s+");
    double average = 0.0d;
    for (int i=1; i < parts.length; ++i) {
        average += Double.parseDouble(parts[i]);
    }
    average /= parts.length - 1;
    char letterGrade = determineGrade(average);

    System.out.println(parts[0] + " " + average + " " + letterGrade);
}

答案 1 :(得分:1)

您可以像以下示例中那样使用BufferedReader。但是您需要自己跟踪文件的结尾。

try (BufferedReader br = new BufferedReader(new FileReader("<path to your file>")));

  for (Item item : list) {

    String line = br.readLine();
    if (line == null) {
      break; // no more lines to read
    }
    // do something with line...

  }
}

答案 2 :(得分:1)

您的代码重复打印平均标记的原因是这里的这种方法

public static double studentAverage(int testQty) throws IOException
    {
        File infile = new File("Grades.txt");
        Scanner scanavg = new Scanner(infile);
        double studentSum = 0;

        scanavg.nextLine();
        scanavg.next();

        for(int i = 1; i <= testQty; i++) {
            studentSum += scanavg.nextDouble();
        }

        double studentAvg = studentSum / testQty;
        return studentAvg;
    }

问题是,尽管您认为自己正在读取连续的行,但实际上,只要执行此方法,您实际上只是在读取文件的第一行,因此最终会出现第一个学生标记。

解决方案

如果您对Streams和java.nio感到满意,则可以使用Files.lines()

进行一些更优雅和更实用的操作
public static void main(String... args) throws IOException {

        // The following line reads each line from your data file and does some
        // with it.
        Files.lines(Paths.get("/path/to/your/file")).forEach(ThisClass::doSomethingWithLine);

        System.out.println("clas average is "+ (classMarks / totalStuds));
    }

    static double classMarks=0; //total marks of the class
    static int totalStuds=0; // total students read until now


    static void doSomethingWithLine(String line) {
        Scanner sc = new Scanner(line);

        // Parse the tokens
        // student name (assuming only first name according to your
        //  example) otherwise use pattern to parse multi part names
        String name = sc.next();

        // parse student marks
        // (you could create a method for this to make things cleaner)
        int subA = sc.nextInt();
        int subB = sc.nextInt();
        int subC = sc.nextInt();
        //calculate average
        double avg = (subA + subB + subC) / 3;

        // calculate class average
        classMarks = classMarks + avg
        totalStuds++;

        //determine grade
        char grade = determineGrade(avg);
        System.out.println(name + " " + avg + " " + grade);
    }