2015-04-10 8 views
1

Я использую bufio для создания цикла for для каждой строки в текстовом файле. Я не знаю, как подсчитать количество строк.Подсчет строк через bufio

scanner := bufio.NewScanner(bufio.NewReader(file)) 

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

ответ

4

Вы могли бы сделать что-то вроде этого:

counter := 0 
for scanner.Scan() { 
    line := scanner.Text() 
    counter++ 
    // do something with your line 
} 
fmt.Printf("Lines read: %d", counter) 
+0

Я надеялся, что bufio существует встроенный метод, но я думаю, что я просто использую это вместо этого. Единственная проблема заключается в том, что я хочу отображать количество строк до того, как я запустил содержимое для циклов. – Mike

+1

См. [Это] (http://stackoverflow.com/a/24563853/1078890) ответ, который может помочь в этом. – IamNaN

+4

@Sladey Чтобы узнать, сколько строк имеет файл, вы должны прочитать все. Это то, что вы не можете изменить. – fuz

-1

Вот мой подход, чтобы сделать задачу:

inputFile, err := os.Open("input.txt") 

if err != nil { 
    panic("Error happend during opening the file. Please check if file exists!") 
    os.Exit(1) 
} 

defer inputFile.Close() 

inputReader := bufio.NewReader(inputFile) 

scanner := bufio.NewScanner(inputReader) 
// Count the words. 
count := 0 
for scanner.Scan() { 
    line := scanner.Text() 
    fmt.Printf("%v\n", line) 
    count++ 
} 
if err := scanner.Err(); err != nil { 
    fmt.Fprintln(os.Stderr, "reading input:", err) 
} 
fmt.Printf("%d\n", count) 
+0

Не используйте 'panic' +' os.Exit' для ошибок, не связанных с программированием (и затем скрыть фактическую причину ошибки!). Вы могли бы просто сделать «log.Fatal (err)». –

1

Держите это просто и быстро. Нет необходимости в буферизации, scanner уже делает это. Не делайте ненужных преобразований string. Например,

package main 

import (
    "bufio" 
    "fmt" 
    "os" 
) 

func lineCount(filename string) (int64, error) { 
    lc := int64(0) 
    f, err := os.Open(filename) 
    if err != nil { 
     return 0, err 
    } 
    defer f.Close() 
    s := bufio.NewScanner(f) 
    for s.Scan() { 
     lc++ 
    } 
    return lc, s.Err() 
} 

func main() { 
    filename := `testfile` 
    lc, err := lineCount(filename) 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    fmt.Println(filename+" line count:", lc) 
} 
+0

Конечно, вы можете упростить конец 'lineCount' только для' return lc, s.Err() '. –

+0

@DaveC: Это правда. – peterSO

0

Как я уже отмечал, принятый ответ терпит неудачу на длинных линиях. Предел по умолчанию - bufio.MaxScanTokenSize, который составляет 64KiB. Поэтому, если ваша линия длиннее 65536 символов, она будет терпеть неудачу. У вас есть два варианта.

  1. Позвоните по номеру scanner.Buffer() и укажите необходимый параметр max. buffer может быть небольшим по умолчанию, потому что Scanner достаточно умен, чтобы выделить новые. Может быть проблемой, если вы заранее не знаете общий размер, например, с интерфейсом vanilla Reader, и у вас есть огромные линии - потребление памяти будет соответственно расти, так как Scanner записывает всю строку.
  2. Recreate scanner во внешнем контуре, это гарантирует, что вы продвинуться дальше:
var scanner *bufio.Scanner 
counter := 0 
for scanner == nil || scanner.Err() == bufio.ErrTooLong { 
    scanner = bufio.NewScanner(reader) 
    for scanner.Scan() { 
     counter++ 
    } 
} 

Проблема с (2) является то, что вы продолжаете выделения и освобождения буферов вместо использования их. Итак, давайте взломать (1) и (2):

var scanner *bufio.Scanner 
buffer := make([]byte, bufio.MaxScanTokenSize) 
counter := 0 
for scanner == nil || scanner.Err() == bufio.ErrTooLong { 
    scanner = bufio.NewScanner(reader) 
    scanner.Buffer(buffer, 0) 
    for scanner.Scan() { 
     counter++ 
    } 
} 
Смежные вопросы