Python: What’s a fast way to read and split a file?
I need to read a file and split it into lines, and also split those lines in half by tab characters, as well as getting rid of all speech marks. At the moment I have a working function. However, it is rather slow:
temp = [] fp = open(fName, "r") for line in fp: temp.append(line.replace("\"","").rstrip("\n").split("\t")) print temp
This splits the file into a list of lists. It could really just be one list, as it would be pretty easy to redivide it into pairs later as long as the order was retained. There must be a faster way of doing this. Could anyone put me on the right track? Thank you! [edit] The file I’m working with is massive, but I’ll add something like it. (Is there a way to upload files on stack overflow?)
"CARMILLA" "35" "JONATHAN R" "AA2" "M" "3" "EMMA" "350" "OLD" "AA"
["CARMILLA", "35", "JONATHON R", "AA2", "M", "3", "EMMA", "350", "OLD", "AA"]
Although my code returns it as a list of lists of 2 strings, which is also fine. Sorry, I should probably have noted that the print statement is standing in for a return statement — since I took this out of a function I changed it to print so it would make more sense here.
If all you want is a printed output, you could just print in your for loop instead of appending to the list.
On what are you basing your assumption that reading and splitting is «rather slow»? How did you measure it?
8 Answers 8
I would think a list comprehension would be faster than calling .append for each line
from itertools import chain with open('file.txt') as f: lines = chain.from_iterable([l.replace(r'"','').rstrip('\n').split('\t',1) for l in f])
EDIT: so it produces a flattened list
>>> ['CARMILLA', '35', 'JONATHAN R', 'AA2', 'M', '3', 'EMMA', '350', 'OLD', 'AA']
The non-flattening version:
with open('file.txt') as f: lines = [l.replace(r'"','').rstrip('\n').split('\t',1) for l in f]
And some timeing, turns out OP’s is the fastest?
import timeit print("chain, list",timeit.timeit(r""" with open('file.txt') as f: lines = chain.from_iterable([l.replace(r'"','').rstrip('\n').split('\t',1) for l in f])""",setup="from itertools import chain",number=1000)) print("flat ",timeit.timeit(r""" with open('file.txt') as f: lines = [l.replace(r'"','').rstrip('\n').split('\t',1) for l in f]""",setup="from itertools import chain",number=1000)) print("op's ",timeit.timeit(r"""temp = [] fp = open('file.txt', "r") for line in fp: temp.append(line.replace("\"","").rstrip("\n").split("\t")) """,number=1000)) print("jamlyks ",timeit.timeit(r""" with open('file.txt', 'rb') as f: r = csv.reader(f, delimiter=' ', skipinitialspace=True) list(chain.from_iterable(r))""",setup="from itertools import chain; import csv",number=1000)) print("lennart ",timeit.timeit(r""" list(csv.reader(open('file.txt'), delimiter='\t', quotechar='"'))""",setup="from itertools import chain; import csv",number=1000))
C:\Users\Henry\Desktop>k.py ('chain, list', 0.04725674146159321) ('my flat ', 0.04629905135295972) ("op's ", 0.04391255644624917) ('jamlyks ', 0.048360870934994915) ('lennart ', 0.04569112379085424)
Статья Python3 5.Работа с файлами,Split(),Цикл for,Список списков
Что бы открыть файл в питоне есть функция open() , которая принимает 2 аргумента , имя файла записанное в виде строки и режим в котором будем работать с файлом :
«r» = режим чтения (значение по умолчанию)
«w» = режим записи(содержимое удаляется) если файла не существует создает новый
«x» = открытие на запись, если файла не существует иначе исключение
«a» = режим дозаписи , изменения сохраняются в конце файла
«b» = чтение в двоичном коде
«t» = текстовый режим (значение по умолчанию)
«+» = запись и чтение
Возможно комбинирование режимов («rb») чтение в двоичном коде
>>> open("sample.txt", "r") # файл находится в папке с питоном >>> open("C:\py\sample.txt", "r") # указывается путь к файлу
# Имя файла , режим работы с ним и кодировка
Функция open() возвращает объект файла , возможно назначить объект переменной что бы обратиться к нему позже
Переменная не будет содержать информацию которая находится в файле , а позволяет использовать методы для чтения и изменения содержимого
Для считывания содержимого файла используется метод read(), метод возвращает строковое представление содержимого файла , которое возможно присвоить переменной
Метод вызывается с помощью (.)
>>> file = open("sample.txt", "r") >>> f = file.read()
>>> file = open("sample.txt", "r") >>> f = file.read() >>> print(f) one,two,three,four,five
Что бы преобразовать строковый объект в список используется метод split() с аргументом разделителя, если вы имеете строку\файл с большим кол-вом (допустим имен написанных через пробел или запятую) использовать метод split() быстрее чем метод append() для создания списка
Берем данные из прошлого примера (one,two,three,four,five) содержимое файла sample.txt
>>> file = open("sample.txt", "r") >>> f = file.read() >>> list = f.split(",") # содержимое файла которое было считано методом read() # разделяем методом split() c запятой в виде разделителя (,) >>> print(list) ['one', 'two', 'three', 'four', 'five']
>>> list[0:3] # напоминалка вывод с 0 по 2 элементов , (3) считается исключением ['one', 'two', 'three']
>>> list.remove("one") >>> print(list) ['two', 'three', 'four', 'five']
Предположим что работаете вы в бухгалтерии , и вот уже пришло время начислять рабочим зарплату , но ваш файл с фамилиями и кол-вом денег которые нужно начислить людям благодаря стараниям некоторой олдскульной бухгалтерши был пофачен и теперь состоит из кучи белеберды все фамилии написаны в ряд с пробелом по примеру (vasya:9000 masha:3700) и так далее.
И теперь что бы разобраться в нем нужно либо переписывать его вручную или же воспользоваться циклом for для удобного вывода
>>> f = open("zarplata.txt", "r") # открываем файл функцией open() с режимом чтения >>> g = f.read() # содержимое файла считывается методом read() и присваивается переменной g >>> zp_list = g.split(" ") # значение переменной g делится методом split() с разделителем (" ") # и присваивается переменной zp_list >>> print(zp_list) # смотрим получившийся список ['vasya:9000', 'fedya:9000', 'masha:8200', 'petya:7700', 'sasha:5950', 'inna:4700'] >>> for name in zp_list: # в конце основного блока цикла всегда ставится двоеточие ":" >>> print(name) # вложенный блок # как работает цикл for читайте чуть ниже vasya:9000 fedya:9000 masha:8200 petya:7700 sasha:5950 inna:4700
Переменная итератора name является временной переменной которая доступна только в цикле for
Переменной name присваивается индекс [0] в списке zp_list и выводит текущее значение переменной name функцией print()
Переменной name присваивается индекс [1] в списке zp_list и выводит текущее значение переменной name функцией print()
И так далее до последнего элемента списка, как только элементы в списке заканчиваются , цикл for перестает работать
Это список в котором каждый элемент является списком(сам не верю что написал эту тавтологию, бред какой то)используя цикл for для разделения элементов списка методом split() и добавления в конечный список методом append()
>>> zp_list = ['vasya:9000', 'fedya:9000', 'masha:8200', 'petya:7700', 'sasha:5950', 'inna:4700'] # список элементов >>> fin_list = [] # пустой список >>> for name in zp_list: >>> sp_list = name.split(",") # деление списка , разделителем (",") >>> fin_list.append(sp_list) # добавление элементов методом append() в конечный список >>> print(fin_list) # функция за пределами цикла для вывода конечного результата [['vasya:9000'], ['fedya:9000'], ['masha:8200'], ['petya:7700'], ['sasha:5950'], ['inna:4700']]
Как работает цикл for в данном примере:
Временная переменная name принимает индекс [0] из списка zp_list , деление переменной name методом split() с разделителем («,») , присвоение полученного значения переменной sp_list .
Добавление в конечный список fin_list методом append() переменной sp_list.
И так далее до последнего элемента , после завершения цикла for
функция print() находится за пределами цикла и выводит конечный список fin_list
Чтение файлов#
Посмотрим как считывать содержимое файлов, на примере файла r1.txt:
! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !
read #
Метод read — считывает весь файл в одну строку.
Пример использования метода read :
In [1]: f = open('r1.txt') In [2]: f.read() Out[2]: '!\nservice timestamps debug datetime msec localtime show-timezone year\nservice timestamps log datetime msec localtime show-timezone year\nservice password-encryption\nservice sequence-numbers\n!\nno ip domain lookup\n!\nip ssh version 2\n!\n' In [3]: f.read() Out[3]: ''
При повторном чтении файла в 3 строке, отображается пустая строка. Так происходит из-за того, что при вызове метода read , считывается весь файл. И после того, как файл был считан, курсор остается в конце файла. Управлять положением курсора можно с помощью метода seek .
readline #
Построчно файл можно считать с помощью метода readline :
In [4]: f = open('r1.txt') In [5]: f.readline() Out[5]: '!\n' In [6]: f.readline() Out[6]: 'service timestamps debug datetime msec localtime show-timezone year\n'
Но чаще всего проще пройтись по объекту file в цикле, не используя методы read. :
In [7]: f = open('r1.txt') In [8]: for line in f: . print(line) . ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !
readlines #
Еще один полезный метод — readlines . Он считывает строки файла в список:
In [9]: f = open('r1.txt') In [10]: f.readlines() Out[10]: ['!\n', 'service timestamps debug datetime msec localtime show-timezone year\n', 'service timestamps log datetime msec localtime show-timezone year\n', 'service password-encryption\n', 'service sequence-numbers\n', '!\n', 'no ip domain lookup\n', '!\n', 'ip ssh version 2\n', '!\n']
Если нужно получить строки файла, но без перевода строки в конце, можно воспользоваться методом split и как разделитель, указать символ \n :
In [11]: f = open('r1.txt') In [12]: f.read().split('\n') Out[12]: ['!', 'service timestamps debug datetime msec localtime show-timezone year', 'service timestamps log datetime msec localtime show-timezone year', 'service password-encryption', 'service sequence-numbers', '!', 'no ip domain lookup', '!', 'ip ssh version 2', '!', '']
Обратите внимание, что последний элемент списка — пустая строка.
Если перед выполнением split , воспользоваться методом rstrip , список будет без пустой строки в конце:
In [13]: f = open('r1.txt') In [14]: f.read().rstrip().split('\n') Out[14]: ['!', 'service timestamps debug datetime msec localtime show-timezone year', 'service timestamps log datetime msec localtime show-timezone year', 'service password-encryption', 'service sequence-numbers', '!', 'no ip domain lookup', '!', 'ip ssh version 2', '!']
seek #
До сих пор, файл каждый раз приходилось открывать заново, чтобы снова его считать. Так происходит из-за того, что после методов чтения, курсор находится в конце файла. И повторное чтение возвращает пустую строку.
Чтобы ещё раз считать информацию из файла, нужно воспользоваться методом seek , который перемещает курсор в необходимое положение.
Пример открытия файла и считывания содержимого:
In [15]: f = open('r1.txt') In [16]: print(f.read()) ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !
Если вызывать ещё раз метод read , возвращается пустая строка:
Но с помощью метода seek можно перейти в начало файла (0 означает начало файла):
После того как с помощью seek курсор был переведен в начало файла, можно опять считывать содержимое:
In [19]: print(f.read()) ! service timestamps debug datetime msec localtime show-timezone year service timestamps log datetime msec localtime show-timezone year service password-encryption service sequence-numbers ! no ip domain lookup ! ip ssh version 2 !