从命令行中查找文件中特定行的字节位置的最快方法是什么?
e.g。
$ linepos myfile.txt 13
5283
我正在为一个大小为几GB的CSV编写解析器,如果解析器停止,我希望能够从最后一个位置恢复。解析器是在Python中,但即使在file.readlines()
上进行迭代也需要很长时间,因为文件中有数百万行。我只想做file.seek(int(command.getoutput("linepos myfile.txt %i" % lastrow)))
,但我找不到shell命令来有效地执行此操作。
编辑:很抱歉这个混乱,但我正在寻找一个非Python解决方案。我已经知道如何从Python中做到这一点。
答案 0 :(得分:3)
来自@Chepner对我的另一个答案的评论:
position = 0 # or wherever you left off last time
try:
with open('myfile.txt') as file:
file.seek(position) # zero in base case
for line in file:
position = file.tell() # current seek position in file
# process the line
except:
print 'exception occurred at position {}'.format(position)
raise
答案 1 :(得分:1)
对文件对象进行迭代会产生完整行结尾的行。您应该只需将len
添加到计数器对象即可获得该位置。您需要根据字符编码(字符字节大小)进行乘法
position = 0 # or wherever you left off last time
try:
with open('myfile.txt') as file: # don't you go correcting me on naming it file. we don't call file directly anyway!
file.seek(position) # zero in base case
for line in file:
position += len(line)
# process the line
except:
# yes, a naked exception. TWO faux pas in one answer?!?
print 'exception occurred at position {}'.format(position)
raise # re-raise to see traceback or what have you
答案 2 :(得分:0)
好吧,如果你的模式很简单,那就很简单了
$ echo -e '#!/bin/bash\necho abracadabra' >/tmp/script
$ pattern=bash
$ sed -rn "0,/$pattern/ {s/^(.*)$pattern.*$/\1/p ;t exit; p; :exit }" /tmp/script \
| wc -c
8
如您所见,这将输出模式中第一个字符的位置,假设文件中的第一个字符的编号为1。
NB 1:sed
习惯在它解析的最后一个字符串中添加一个尾随换行符,因此,当我们取pattern
之前的一部分行时,输出中的字节数应该是7(计算他们→#!/bin/
),但wc -c
实际上看起来像
$ sed -rn "0,/$pattern/ {s/^(.*)$pattern.*$/\1/p ;t exit; p; :exit }" /tmp/script \
| hexdump -C
00000000 23 21 2f 62 69 6e 2f 0a |#!/bin/.|
00000008
如果你正在寻找EOF,这可能是麻烦的潜在根源。我想不出一个更合适的案例,我只想指出这一点。
注意2:如果模式包含特殊字符,则sed将失败。如果你能提供一个你想要的例子,我可以逃脱它。
注意3:这假设pattern
是唯一的。如果您将停止在pattern
的第二个或第三个实例上阅读该文件,则无效。
更新。 我找到了一种更简单的方法。
$ grep -bo bash <<< '#!/bin/bash'
7:bash
对于GNU grep,有两个选项:
-b, --byte-offset
Print the 0-based byte offset within the input file before each line of
output. If -o (--only-matching) is specified, print the offset of the
matching part itself.
我建议使用grep,因为如果指定-F
键,它会将模式视为一个简单的字符串。
$ grep -F '!@##$@#%%^%&*%^&*(^)((**%%^@#' <<<'!@##$@#%%^%&*%^&*(^)((**%%^@#'
!@##$@#%%^%&*%^&*(^)((**%%^@#