Я новичок в языке Java и не могу понять, как читать по одной строке из текстового файла и получать среднее значение для этой строки.

Мой рабочий код до сих пор получает среднее значение для всего файла:

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

public class NumAverage { 
    public static void main(String[] args) throws IOException { 
        Scanner keyboard = new Scanner(System.in); 

        File myFile = new File("Num.txt"); 
        Scanner inputFile = new Scanner(myFile); 

        int numbersCounter = 0;  
        int sum = 0; 

        while (inputFile.hasNext()) { 
            int numList = inputFile.nextInt(); 

            sum = sum + numList; 
            numbersCounter++; 
        } 

        System.out.println("Average: " + (sum/numbersCounter)); 

        inputFile.close(); 
    } 
}

Так выглядит текстовый файл

 1 2 3 4
 5 6 7 8 
1
Murder face 2 Май 2016 в 01:10

6 ответов

Лучший ответ

Вы должны изучить API потоков Java (знание шаблона декоратора упрощает его понимание).

Для вашего случая мы можем сделать:

FileInputStream stream = new FileInputStream("nums.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
String line;

while((line = reader.readLine()) != null) {
    StringTokenizer tokenizer = new StringTokenizer(line, " ");
    int tokens = tokenizer.countTokens();
    float average = 0;

    while(tokenizer.hasMoreTokens()) {
        String token = tokenizer.nextToken();
        int value = Integer.valueOf(token);
        average += value;
    }

    System.out.println(average / tokens);
}

В первой строке я создаю FileInputStream, который позволяет нам читать из файла.

Во второй строке я украшаю stream как InputStreamReader, а затем как BufferedReader (во второй строке есть отличный API для чтения ввода построчно).

Затем я перебираю ваш файл построчно (используя метод readLine() в цикле) и с помощью StringTokenizer разбиваю строку на токены.

Во втором цикле делаю все необходимые расчеты.

Конечно, вам нужно помнить об исключениях (я опустил их, например, для простоты).

Еще одна вещь, о которой стоит упомянуть - вам необходимо знать, что countTokens () следует использовать перед потреблением токенов - в противном случае он вернет неправильное значение (он возвращает число из того, сколько вы можете вызвать nextToken() до получения исключения).

1
Tomasz Dzieniak 1 Май 2016 в 23:38

Я думаю, вам также нужно проверить наличие «\ n» (новая строка) и распечатать среднее значение внутри цикла:

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

public class NumAverage{ 
public static void main(String[] args) throws IOException{ 
Scanner keyboard = new Scanner(System.in); 

File myFile = new File("Num.txt"); 
Scanner inputFile = new Scanner(myFile); 

int numbersCounter = 0;  
int sum = 0; 

while (inputFile.hasNext()) 
{ 
    if(inputFile.hasNextInt(){
        int numList = inputFile.nextInt(); 
        sum = sum + numList; 
        numbersCounter++;
    }
    if(inputFile.next().Equals("\n"){
        System.out.println("Average: " + (sum/numbersCounter));
        sum = 0;
        numbersCounter=0;
    }

} 



inputFile.close(); 

} }

0
Luís Pedro Gonçalves 2 Май 2016 в 07:24

У объекта Scanner есть функция scanner.nextLine(). Она возвращает строку, которую вы можете обрабатывать как серию чисел, потому что вы знаете формат файла.

 String[] myNumbersArray = myNumbers.split(" ");
 for (String s : myNumbersArray) {
      int myNumber = Integer.parseInt(s);
 }
0
user2651804 1 Май 2016 в 22:35

Вам понадобится две петли. Один для перебора каждой строки файла и один для перебора чисел в файле. Изменен ваш код для использования двух сканеров:

package com.test;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;

public class TestAverageFromFileLines {

    public static void main(String[] args) throws FileNotFoundException {

        File myFile = new File("Num.txt");
        try (Scanner input = new Scanner(myFile)) {
            while (input.hasNextLine()) {
                String line = input.nextLine();

                int numbersCounter = 0;
                int sum = 0;

                try (Scanner lineScanner = new Scanner(line)) {
                    while (lineScanner.hasNext()) {
                        int numList = lineScanner.nextInt();
                        sum = sum + numList;
                        numbersCounter++;
                    }
                }
                System.out.println("Average: " + ((double)sum / numbersCounter));
            }
        }
    }

}

Кроме того, деление целых чисел в Java по умолчанию обрезает дробную часть. Следовательно, чтобы заставить Java выполнять деление без усечения, вам нужно привести один из операндов к типу float или double.

1
Nazaret K. 1 Май 2016 в 22:49

Попробуй это.

File myFile = new File("Num.txt"); 
try (Scanner c = new Scanner(myFile)) {
    while (c.hasNextLine()) {
        System.out.println("Average: " +
            Stream.of(c.nextLine().split("\\s+"))
                .mapToInt(x -> Integer.parseInt(x))
                .average().getAsDouble());
    }
}

Результат:

Average: 2.5
Average: 6.5
1
saka1029 1 Май 2016 в 22:45

Вы можете использовать Files.lines() для создания потока строк текста, затем проанализировать каждую строку в массив чисел и усреднить их.

    Files.lines(Paths.get("nums.txt"))
            .map(str -> str.split(" "))   
            .mapToDouble(arr -> Arrays.stream(arr).mapToInt(Integer::valueOf).average().orElse(0.0))
            .forEach(avg -> System.out.println("Average: " + avg));

Files.lines() заботится обо всех операциях ввода-вывода файла и создает Stream<String>, который позволяет лениво обрабатывать каждую строку при ее чтении из файла. Это действительно полезно, если когда-нибудь вам понадобится иметь дело с очень большими файлами, которые не помещаются в памяти, поскольку каждая строка читается только после того, как предыдущая строка была полностью обработана Stream. По завершении он автоматически закроет файл для вас.

Следующая строка берет каждую строку в файле и преобразует ее в массив строк, по одной для каждого числа. В этот момент поток меняется с Stream<String> на Stream<String[]>

Следующая строка преобразует каждый String [] в число, которое представляет собой среднее значение чисел в строке. Он делает это, беря массив строк и создавая из него поток с помощью Arrays.stream(), превращая каждую строку в целое число с помощью Integer.valueOf(), а затем вызывая average(), чтобы взять весь поток целые числа и вычислить среднее. На данный момент поток теперь является DoubleStream.

В следующей строке каждое среднее значение печатается.

Вся последовательность операций происходит в каждой строке, поэтому среднее значение первой строки печатается до того, как следующая строка будет считана из файла.

2
Hank D 2 Май 2016 в 13:34