Python f.seek 导致 OSError [Errno 22] 如果手动编辑文本文件但如果程序输出到文件则没有错误
Python f.seek caused OSError [Errno 22] if manually edit the text file but no error if program output to file
我正在尝试从文本文件中获取最后一行,我使用的解决方案是
What is the most efficient way to get first and last line of a text file?
def read_last_line(filename):
with open(filename, "rb") as f:
first = f.readline()
if f.read(1) == '':
return first
f.seek(-2, 2) # Jump to the second last byte.
while f.read(1) != b"\n": # Until EOL is found...
f.seek(-2, 1) # ...jump back the read byte plus one more.
last = f.readline() # Read last line.
return last.decode('ascii')
如果文件被另一个 script/program 修改,它设法成功获取文本文件的最后一行,但是当我使用 Notepad++
修改文本文件时,与另一个 Notepad++
的修改完全相同 script/program,会抛出如下异常:
in read_last_line
f.seek(-2, 2)
OSError: [Errno 22] Invalid argument
我想做的是,我使用 watchdog
来检查是否有文件更改,并且在修改时我会在修改后的文件上调用 read_last_line
。
示例文件
11/26/2020 2:05:12 PM Time Updated: +2ms Regular Update
11/26/2020 2:06:13 PM Time Updated: +4ms Regular Update
11/26/2020 2:07:13 PM Time Updated: +1ms Regular Update
我是如何调用函数的:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import ntpath
class FileEventHandler(FileSystemEventHandler):
def __init__(self, filetowatch):
self.file = filetowatch
def on_modified(self, event):
modified_file = ntpath.basename(event.src_path)
if modified_file == self.file:
read_last_line(event.src_path)
if __name__ == "__main__":
event_handler = FileEventHandler("sample.txt")
observer = Observer()
observer.schedule(event_handler, path='C:/Program Files (x86)/SomeTime', recursive=False)
observer.start()
我可以知道是否有人知道导致错误的原因吗?
平台:Windows10,Python3.7.4
更新 - 答案
所以这个错误是因为 fread(1) == ''
使用 falsetru 的解决方案修复的。
它没有按我预期的方式执行的原因是因为文本编辑器 删除了 示例文件并使用相同的文件名创建了一个文件,因此 fread(1)==''
被触发(抛出)并且使用script/program修改示例文件并没有抛出只是因为我没有删除文件。
如果只有一个(带/不带尾随换行符),则永远不会满足 while 循环条件。
这导致 f.seek(-2, 1)
尝试查找导致错误的负文件位置。
保护这种情况(防止试图超出文件开头),使用 .tell()
让您知道当前文件位置:
while f.tell() >= 1 and f.read(1) != b"\n":
或者您可以使用 seek(..)
return 值:
while f.read(1) != b"\n":
if f.seek(-2, 1) == 0:
break # prevent going beyond file beginning.
更新
在二进制模式下 <io object>.read()
return 字节对象。在 if
条件下,代码将字节对象与字符串 ''
进行比较;由于类型差异,它总是会失败。
更改为与字节文字进行比较将解决此问题。
if f.read(1) == b'':
return first
我正在尝试从文本文件中获取最后一行,我使用的解决方案是 What is the most efficient way to get first and last line of a text file?
def read_last_line(filename):
with open(filename, "rb") as f:
first = f.readline()
if f.read(1) == '':
return first
f.seek(-2, 2) # Jump to the second last byte.
while f.read(1) != b"\n": # Until EOL is found...
f.seek(-2, 1) # ...jump back the read byte plus one more.
last = f.readline() # Read last line.
return last.decode('ascii')
如果文件被另一个 script/program 修改,它设法成功获取文本文件的最后一行,但是当我使用 Notepad++
修改文本文件时,与另一个 Notepad++
的修改完全相同 script/program,会抛出如下异常:
in read_last_line
f.seek(-2, 2)
OSError: [Errno 22] Invalid argument
我想做的是,我使用 watchdog
来检查是否有文件更改,并且在修改时我会在修改后的文件上调用 read_last_line
。
示例文件
11/26/2020 2:05:12 PM Time Updated: +2ms Regular Update
11/26/2020 2:06:13 PM Time Updated: +4ms Regular Update
11/26/2020 2:07:13 PM Time Updated: +1ms Regular Update
我是如何调用函数的:
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import ntpath
class FileEventHandler(FileSystemEventHandler):
def __init__(self, filetowatch):
self.file = filetowatch
def on_modified(self, event):
modified_file = ntpath.basename(event.src_path)
if modified_file == self.file:
read_last_line(event.src_path)
if __name__ == "__main__":
event_handler = FileEventHandler("sample.txt")
observer = Observer()
observer.schedule(event_handler, path='C:/Program Files (x86)/SomeTime', recursive=False)
observer.start()
我可以知道是否有人知道导致错误的原因吗?
平台:Windows10,Python3.7.4
更新 - 答案
所以这个错误是因为 fread(1) == ''
使用 falsetru 的解决方案修复的。
它没有按我预期的方式执行的原因是因为文本编辑器 删除了 示例文件并使用相同的文件名创建了一个文件,因此 fread(1)==''
被触发(抛出)并且使用script/program修改示例文件并没有抛出只是因为我没有删除文件。
如果只有一个(带/不带尾随换行符),则永远不会满足 while 循环条件。
这导致 f.seek(-2, 1)
尝试查找导致错误的负文件位置。
保护这种情况(防止试图超出文件开头),使用 .tell()
让您知道当前文件位置:
while f.tell() >= 1 and f.read(1) != b"\n":
或者您可以使用 seek(..)
return 值:
while f.read(1) != b"\n":
if f.seek(-2, 1) == 0:
break # prevent going beyond file beginning.
更新
在二进制模式下 <io object>.read()
return 字节对象。在 if
条件下,代码将字节对象与字符串 ''
进行比较;由于类型差异,它总是会失败。
更改为与字节文字进行比较将解决此问题。
if f.read(1) == b'':
return first