将文件指针倒回到上一行的开头

时间:2012-11-20 16:27:28

标签: python file seek

我正在进行文本处理并使用'readline()'函数,如下所示:

ifd = open(...)
for line in ifd:
   while (condition)
         do something...
         line = ifd.readline()
         condition = ....

#Here当条件变为false时我需要倒回指针,以便'for'循环再次读取同一行。

ifd.fseek()后跟readline给我一个'\ n'字符。如何倒回指针以便再次读取整行。

>>> ifd.seek(-1,1)
>>> line = ifd.readline()
>>> line
'\n'

这是我的代码

labtestnames = sorted(tmp)
#Now read each line in the inFile and write into outFile
ifd = open(inFile, "r")
ofd = open(outFile, "w")
#read the header
header = ifd.readline() #Do nothing with this line. Skip
#Write header into the output file
nl = "mrn\tspecimen_id\tlab_number\tlogin_dt\tfluid"
offset = len(nl.split("\t"))
nl = nl + "\t" + "\t".join(labtestnames)
ofd.write(nl+"\n")
lenFields = len(nl.split("\t"))


print "Reading the input file and converting into modified file for further processing (correlation analysis etc..)"

prevTup = (0,0,0)
rowComplete = 0
k=0
for line in ifd:
    k=k+1
    if (k==200): break

    items = line.rstrip("\n").split("\t")
    if((items[0] =='')):
        continue
    newline= list('' for i in range(lenFields))
    newline[0],newline[1],newline[3],newline[2],newline[4] = items[0], items[1], items[3], items[2], items[4]
    ltests = []
    ltvals = []
    while(cmp(prevTup, (items[0], items[1], items[3])) == 0): # If the same mrn, lab_number and specimen_id then fill the same row. else create a new row.
        ltests.append(items[6])
        ltvals.append(items[7])
        pos = ifd.tell()
        line = ifd.readline()
        prevTup = (items[0], items[1], items[3])
        items = line.rstrip("\n").split("\t")
        rowComplete = 1

    if (rowComplete == 1): #If the row is completed, prepare newline and write into outfile
        indices = [labtestnames.index(x) for x in ltests]
        j=0
        ifd.seek(pos)
        for i in indices:
            newline[i+offset] = ltvals[j]
            j=j+1

    if (rowComplete == 0): # 
        currTup = (items[0], items[1], items[3])
        ltests = items[6]
        ltvals = items[7]
        pos = ifd.tell()
        line = ifd.readline()
        items = line.rstrip("\n").split("\t")
        newTup = (items[0], items[1], items[3])
        if(cmp(currTup, newTup) == 0):
            prevTup = currTup
            ifd.seek(pos)
            continue
        else:
            indices = labtestnames.index(ltests)
            newline[indices+offset] = ltvals

    ofd.write(newline+"\n")

2 个答案:

答案 0 :(得分:1)

使用itertools.groupby可以更简单地处理问题。 groupby可以聚集处理相同mrn,samples_id和lab_num的所有连续行。

执行此操作的代码是

for key, group in IT.groupby(reader, key = mykey):

其中reader遍历输入文件的行,mykey

定义
def mykey(row):
    return (row['mrn'], row['specimen_id'], row['lab_num'])

reader中的每一行都会传递给mykey,所有具有相同键的行都会聚集在同一group中。


虽然我们正在努力,但我们不妨使用csv module将每一行读入dict(我称之为row)。这使我们不必处理像line.rstrip("\n").split("\t")这样的低级字符串操作,而不是通过索引号引用列(例如row[3]),我们可以编写更高级别的术语,例如{ {1}}。


row['lab_num']

产量

import itertools as IT
import csv

inFile = 'curious.dat'
outFile = 'curious.out'

def mykey(row):
    return (row['mrn'], row['specimen_id'], row['lab_num'])

fieldnames = 'mrn specimen_id date    lab_num Bilirubin   Lipase  Calcium Magnesium   Phosphate'.split()

with open(inFile, 'rb') as ifd:
    reader = csv.DictReader(ifd, delimiter = '\t')
    with open(outFile, 'wb') as ofd:
        writer = csv.DictWriter(
            ofd, fieldnames, delimiter = '\t', lineterminator = '\n', )
        writer.writeheader()
        for key, group in IT.groupby(reader, key = mykey):
            new = {}
            row = next(group)
            for key in ('mrn', 'specimen_id', 'date', 'lab_num'):
                new[key] = row[key]
                new[row['labtest']] = row['result_val']                
            for row in group:
                new[row['labtest']] = row['result_val']
            writer.writerow(new)

答案 1 :(得分:0)

这似乎是yield expressions的完美用例。请考虑以下示例,该文件从文件中打印行,随机重复其中一些行:

def buflines(fp):
    r = None
    while True:
        r = yield r or next(fp)
        if r:
            yield None

from random import randint

with open('filename') as fp:
    buf = buflines(fp)
    for line in buf:
        print line
        if randint(1, 100) > 80:
            print 'ONCE AGAIN::'
            buf.send(line)

基本上,如果你想再次处理一个项目,你可以send回到生成器。在下一次迭代中,您将再次阅读相同的项目。