python - 来自不同进程的文件同时读/写操作:在 Windows 上工作但在 Linux 上不工作
问题描述
我正在使用 .log 文件中的数据创建一个 SQLite 数据库。机器每次执行操作时都会更新日志文件。我在 Windows 中所做的是监视这个文件的变化,一旦它被修改 - 机器通过串行通信在外部进行修改,但我通过在记事本中打开文件并添加新行来模拟这种行为 - 读取新行并将数据放入数据库。
问题是当我尝试对我的 Linux 机器做同样的事情时,因为显然 python 程序即使在文件被更新和保存后也看不到文件中的任何修改。尽管如此,如果我在程序中关闭并重新打开文件以重新读取它,修改就在那里(但我仍然无法检测到新的修改)。
实际上,我已经在运行在 Raspbian 上的 Raspberry Pi 3 B+ 上测试了相同的代码,并且它按预期工作:检测到修改后的套件并将数据添加到数据库中。
.log 文件的格式如下所示。
01 (PB) 008 Pa 6.01 bar 12/11/2055 07:25:17 01 (PB) 008 Pa 6.01 bar 12/11/2055 07:26:39 01 (PB) 009 Pa 6.00 bar 12/11/2055 07:29:45
这是我正在使用的代码:
import re
import sqlite3
import os, time
if __name__=='__main__':
fd = open('putty.log', 'r')
# Ici on crée la base de données qui gardera les résultats des tests
connection = sqlite3.connect('banc_tests.db')
cursor = connection.cursor()
create_db = """
CREATE TABLE tests (
reference VARCHAR(15),
num_serie VARCHAR(15),
operation TINYINT,
resultat CHAR(2),
fuite SMALLINT,
unite VARCHAR(5),
pression FLOAT,
pUnite VARCHAR(5),
date DATE,
time TIME
);
"""
cursor.execute(create_db)
# Here we look for the testing bank frame's format with regular expressions
# For now we are ignoring all information about low pressure, PE test, etc.
while 1:
where = fd.tell() # Garde la position actuelle du curseur dans le fichier
line = fd.readline() # On lit la ligne suivante
if not line:
time.sleep(1)
fd.seek(where) #Si il n'y a rien à lire on retourne à la position précédente.
else:
# The ([\+\-]?\d*)\s*(\w*) segment in intended to ignore whitespaces in the faulty testing lines
# as well as to grab the leak pressure for ordinary tests. To change it back to the original
# version, it suffices to replace every * by a +.
print(line)
found = re.findall(r'^\s+(\d+)\s+\((\w+)\)\s+([\+\-]?\d*)\s*(\w*)\s+(\d+\.?\d+)\s+(\w+).*\s(\d+)/(\d+)/(\d+)\s+(\d+:\d+:\d+)', line)
# La commande findall retourne une tuple dans une liste, donc ici j'enlève la tuple et laisse
# juste la liste avec les éléments dedans.
if found:
temp = list(found[0])
insert_values = """
INSERT INTO tests (reference, num_serie, operation, resultat, fuite, unite, pression, pUnite, date, time)
VALUES ("{ref}", "{num_ser}", "{op}", "{res}", "{fuite}", "{unt}", "{pression}", "{pUnt}", "{date}", "{time}"); """
insert_command = insert_values.format(ref='', num_ser='', op=temp[0], res=temp[1], fuite=temp[2], unt=temp[3], pression=temp[4], pUnt=temp[5], date='{}-{}-{}'.format(temp[8], temp[7], temp[6]), time=temp[9])
cursor.execute(insert_command)
connection.commit()
我认为这是 open() 函数阻塞行为的问题,所以我尝试将os.O_NONBLOCK标志与fcntl一起使用;但是,它没有用。
有没有人知道什么可能导致 Linux(Debian 10 Bluster)和 Windows 之间的这种不同行为?我能做些什么来解决Linux端的问题?
解决方案
我做了一些研究,我发现了问题。这是因为inode
在编辑器中保存后文件已更改。
您可以使用vim
并设置set backupcopy=yes
来防止这种行为(http://vimdoc.sourceforge.net/htmldoc/options.html#'backupcopy')
要观察这种行为,您可以使用ls -li
它将向您显示inode
文件的。
pawel@pawel-XPS-15-9570:~/test$ ls -li putty.log
10263515 -rw-r--r-- 1 pawel pawel 87 wrz 5 14:10 putty.log
pawel@pawel-XPS-15-9570:~/test$ echo 'test' >> putty.log
pawel@pawel-XPS-15-9570:~/test$ ls -li putty.log
10263515 -rw-r--r-- 1 pawel pawel 92 wrz 5 14:14 putty.log
pawel@pawel-XPS-15-9570:~/test$ vim putty.log
pawel@pawel-XPS-15-9570:~/test$ ls -li putty.log
10263513 -rw-r--r-- 1 pawel pawel 97 wrz 5 14:14 putty.log
pawel@pawel-XPS-15-9570:~/test$
第一列呈现inode
。正如您在 vim 编辑后看到的那样,它已更改,这就是您的脚本无法看到这些更改的原因(因为编辑器覆盖了此文件)。
推荐阅读
- arduino - arduino 可以将鼠标移动到屏幕上的确切位置吗?
- liquid - 可以治疗吗?作为文本而不是过滤器?
- python - 如果列及其值存在于两个数据框中,如何合并两个数据框?
- ruby-on-rails - 如果 Spree Deface Original 已更改,是否会引发错误和/或单元测试?
- performance - 为什么在 L1 缓存中使用带有存储指令块预取的 MFENCE?
- php - PHP/Laravel:在 PHP 中创建 JSON 时如何插入新的 json 字段?
- oracle - 如何在较低环境中测试数据库脚本的所有环境配置
- apache - 是否可以使用 Apache 在 docker 容器中配置虚拟主机?
- go - 在 Goland IDE 中导入本地 Go 模块
- intellij-idea - 在 Kotlin 项目中插入 TornadoFx