简体   繁体   English

Python f.seek 导致 OSError [Errno 22] 如果手动编辑文本文件但如果将 output 编程到文件则没有错误

[英]Python f.seek caused OSError [Errno 22] if manually edit the text file but no error if program output to file

I am trying to get last line from a text file, which I used the solution from 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')

It managed to get the last line of the text file successfully if the file is modified by another script/program, but when I modify the text file using Notepad++ the exact same modification as another script/program, it will throw the following exception:如果文件被另一个脚本/程序修改,它成功地获取了文本文件的最后一行,但是当我使用Notepad++修改文本文件时,与另一个脚本/程序的修改完全相同,它会抛出以下异常:

in read_last_line
    f.seek(-2, 2)
OSError: [Errno 22] Invalid argument

What I am trying to do is, I used watchdog to check if there's file changes, and on modify I will call read_last_line on the modified file.我想要做的是,我使用watchdog检查是否有文件更改,并且在修改时我将在修改后的文件上调用read_last_line

Sample file示例文件

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

How I am calling the function:我如何称呼 function:

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()

May I know if anyone know what is causing the error?我可以知道是否有人知道导致错误的原因?

Platform: Windows 10, Python 3.7.4平台:Windows 10、Python 3.7.4

UPDATE - ANSWER更新 - 答案

So the error was because of fread(1) == '' which was fixed using falsetru 's solution.所以错误是因为fread(1) == ''使用falsetru的解决方案修复的。

The reason why it is not performing the way I expected was because text editor deletes the sample file and create a file using the same file name, therefore fread(1)=='' was triggered (which throws) and using script/program to modify the sample file did not throw simply because I did not delete the file.它没有按我预期的方式执行的原因是因为文本编辑器删除了示例文件并使用相同的文件名创建了一个文件,因此触发了fread(1)==''并使用脚本/程序修改示例文件并没有仅仅因为我没有删除文件而抛出。

If there's only a single (with / without trailing newline), while loop condition will never be met.如果只有一个(带/不带尾随换行符),则永远不会满足 while 循环条件。

That cause f.seek(-2, 1) to try to seek to negative file position which causes the error.这导致f.seek(-2, 1)尝试寻找负文件 position 导致错误。

Guard such case (prevent trying to seek beyond the file beginning), using .tell() which let you know current file position:保护这种情况(防止试图超越文件开头),使用.tell()让你知道当前文件 position:

        while f.tell() >= 1 and f.read(1) != b"\n":

or you can use seek(..) return value:或者您可以使用seek(..)返回值:

        while f.read(1) != b"\n":
            if f.seek(-2, 1) == 0:
                break  # prevent going beyond file beginning.

UPDATE更新

In binary mode <io object>.read() return bytes object.在二进制模式下<io object>.read()返回字节 object。 In if condition, the code is comparing the bytes object with a string '' ;if条件下,代码将字节 object 与字符串''进行比较; which will always fail because of type difference.由于类型差异,它总是会失败。 Changing to compare with bytes literal will fix the issue.更改为与字节文字进行比较将解决此问题。

        if f.read(1) == b'':
            return first

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM