以下是为统信UOS设计的Kivy应用本地存储完整解决方案,包含SQLite和JSON两种方式的详细实现:
统信UOS Kivy本地存储方案
一、存储路径规划(符合UOS规范)
1. 应用数据目录结构
~/.local/share/yourapp/ # 统信UOS推荐的应用数据位置
├── databases/ # SQLite数据库
│ └── app_data.db
├── json/ # JSON存储
│ ├── config.json
│ └── userdata.json
└── cache/ # 临时缓存
2. 路径获取方法
from kivy.app import App
import os
import platform
def get_storage_path():
"""获取符合统信UOS规范的存储路径"""
app = App.get_running_app()
# 统信UOS特殊处理
if platform.system() == 'Linux' and 'UOS' in os.uname().version:
base = os.path.expanduser('~/.local/share')
else:
base = app.user_data_dir
paths = {
'db': os.path.join(base, app.name, 'databases'),
'json': os.path.join(base, app.name, 'json'),
'cache': os.path.join(base, app.name, 'cache')
}
# 创建目录
for path in paths.values():
os.makedirs(path, exist_ok=True)
return paths
二、SQLite数据库集成
1. 数据库初始化(带UOS兼容性处理)
import sqlite3
from kivy.clock import Clock
class DatabaseManager:
def __init__(self):
self.paths = get_storage_path()
self.db_path = os.path.join(self.paths['db'], 'app_data.db')
self._init_db()
def _init_db(self):
"""初始化数据库表结构"""
def _actual_init(dt):
with self.get_connection() as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password_hash TEXT,
last_login TIMESTAMP
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT
)
''')
conn.commit()
# 统信UOS下需要延迟执行
Clock.schedule_once(_actual_init, 0)
def get_connection(self):
"""获取数据库连接(带UOS文件锁处理)"""
conn = sqlite3.connect(self.db_path, timeout=30)
conn.execute('PRAGMA journal_mode=WAL') # 统信UOS建议的日志模式
return conn
2. 增删改查封装
class DatabaseManager:
# ...接上...
def add_user(self, username, password_hash):
"""添加用户"""
try:
with self.get_connection() as conn:
conn.execute(
'INSERT INTO users (username, password_hash) VALUES (?, ?)',
(username, password_hash)
)
return True
except sqlite3.IntegrityError:
return False
def get_setting(self, key, default=None):
"""获取设置项"""
with self.get_connection() as conn:
cursor = conn.cursor()
cursor.execute('SELECT value FROM settings WHERE key = ?', (key,))
result = cursor.fetchone()
return result[0] if result else default
def update_setting(self, key, value):
"""更新设置项"""
with self.get_connection() as conn:
conn.execute(
'''INSERT OR REPLACE INTO settings (key, value)
VALUES (?, ?)''',
(key, value)
)
3. KV界面绑定示例
<LoginForm>:
username: username_input
password: password_input
BoxLayout:
orientation: 'vertical'
TextInput:
id: username_input
hint_text: "用户名"
TextInput:
id: password_input
hint_text: "密码"
password: True
Button:
text: "登录"
on_press: app.db_manager.login(root.username.text, root.password.text)
三、JSON存储方案
1. JSON管理器实现
import json
from threading import Lock
from kivy.utils import platform
class JSONStorage:
_instance = None
_lock = Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._init()
return cls._instance
def _init(self):
self.paths = get_storage_path()
# 统信UOS下需要更严格的文件权限
self.umask = 0o077 if platform == 'linux' and 'UOS' in os.uname().version else None
def _safe_write(self, path, data):
"""安全的原子化写入(兼容UOS文件系统)"""
temp_path = f"{path}.tmp"
with open(temp_path, 'w', encoding='utf-8') as f:
if self.umask is not None:
old_mask = os.umask(self.umask)
json.dump(data, f, ensure_ascii=False, indent=2)
if self.umask is not None:
os.umask(old_mask)
os.replace(temp_path, path)
def save_config(self, config_data):
"""保存配置"""
path = os.path.join(self.paths['json'], 'config.json')
self._safe_write(path, config_data)
def load_config(self):
"""加载配置"""
path = os.path.join(self.paths['json'], 'config.json')
try:
with open(path, 'r', encoding='utf-8') as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
return {}
2. 配置自动保存装饰器
def autosave_json(func):
"""自动保存JSON的装饰器"""
def wrapper(self, *args, **kwargs):
result = func(self, *args, **kwargs)
self._save_to_disk()
return result
return wrapper
class AppConfig:
def __init__(self):
self.data = JSONStorage().load_config()
@autosave_json
def set_theme(self, theme_name):
self.data['theme'] = theme_name
@autosave_json
def set_language(self, lang_code):
self.data['language'] = lang_code
def _save_to_disk(self):
JSONStorage().save_config(self.data)
四、数据加密(符合UOS安全规范)
1. 使用统信UOS密钥环
from cryptography.fernet import Fernet
import keyring
class DataEncryptor:
def __init__(self, service_name):
self.service = service_name
self._setup_key()
def _setup_key(self):
"""从统信UOS密钥环获取加密密钥"""
try:
key = keyring.get_password(self.service, 'fernet_key')
if not key:
key = Fernet.generate_key().decode()
keyring.set_password(self.service, 'fernet_key', key)
self.cipher = Fernet(key.encode())
except Exception as e:
print(f"密钥环访问失败,使用临时密钥: {e}")
self.cipher = Fernet.generate_key()
def encrypt(self, data: str) -> bytes:
"""加密数据"""
return self.cipher.encrypt(data.encode())
def decrypt(self, token: bytes) -> str:
"""解密数据"""
return self.cipher.decrypt(token).decode()
2. 安全存储实现
class SecureStorage:
def __init__(self):
self.encryptor = DataEncryptor("com.yourapp.storage")
self.db_manager = DatabaseManager()
def save_credential(self, username, password):
"""安全存储凭据"""
encrypted = self.encryptor.encrypt(password)
self.db_manager.update_setting(
f"cred_{username}",
encrypted.hex() # 存储为十六进制字符串
)
def get_credential(self, username):
"""获取解密后的凭据"""
encrypted_hex = self.db_manager.get_setting(f"cred_{username}")
if encrypted_hex:
return self.encryptor.decrypt(bytes.fromhex(encrypted_hex))
return None
五、完整示例:笔记应用
1. 数据库模型
class NoteDatabase(DatabaseManager):
def __init__(self):
super().__init__()
def create_note(self, title, content, tags=""):
with self.get_connection() as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO notes (title, content, tags, created_at)
VALUES (?, ?, ?, datetime('now'))
''', (title, content, tags))
return cursor.lastrowid
def get_notes(self, search_term=None):
with self.get_connection() as conn:
cursor = conn.cursor()
if search_term:
cursor.execute('''
SELECT * FROM notes
WHERE title LIKE ? OR content LIKE ?
ORDER BY created_at DESC
''', (f"%{search_term}%", f"%{search_term}%"))
else:
cursor.execute('SELECT * FROM notes ORDER BY created_at DESC')
return cursor.fetchall()
2. KV界面实现
<NoteEditor>:
title: title_input
content: content_input
BoxLayout:
orientation: 'vertical'
TextInput:
id: title_input
hint_text: "标题"
size_hint_y: None
height: '50sp'
ScrollView:
TextInput:
id: content_input
hint_text: "内容"
multiline: True
padding: [10, 10]
BoxLayout:
size_hint_y: None
height: '40sp'
Button:
text: "保存"
on_press: app.save_note(root.title.text, root.content.text)
Button:
text: "加载"
on_press: app.load_notes()
3. JSON配置集成
class NoteApp(App):
def build(self):
self.db = NoteDatabase()
self.config = AppConfig()
return NoteEditor()
def save_note(self, title, content):
note_id = self.db.create_note(title, content)
recent = self.config.data.get('recent_notes', [])
recent.append(note_id)
self.config.set('recent_notes', recent[-10:]) # 只保留最近10条
def on_start(self):
# 应用启动时加载主题
theme = self.config.get('theme', 'light')
self.set_theme(theme)
六、统信UOS特殊优化
1. 数据库备份机制
def backup_database():
"""统信UOS下的定时备份"""
paths = get_storage_path()
db_path = os.path.join(paths['db'], 'app_data.db')
backup_dir = os.path.join(paths['db'], 'backups')
os.makedirs(backup_dir, exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_path = os.path.join(backup_dir, f'backup_{timestamp}.db')
# 使用统信UOS的rsync工具进行高效备份
if platform == 'linux' and 'UOS' in os.uname().version:
os.system(f'rsync -ah --progress {db_path} {backup_path}')
else:
shutil.copy2(db_path, backup_path)
# 清理旧备份(保留最近7天)
for f in os.listdir(backup_dir):
if f.startswith('backup_') and f.endswith('.db'):
path = os.path.join(backup_dir, f)
if os.stat(path).st_mtime < time.time() - 7*86400:
os.remove(path)
2. 性能优化建议
-
SQLite调优:
conn.execute("PRAGMA synchronous = NORMAL") # 统信UOS推荐设置 conn.execute("PRAGMA cache_size = -10000") # 10MB缓存
-
JSON大数据处理:
# 使用ijson流式处理大JSON文件 import ijson def parse_large_json(path): with open(path, "rb") as f: for item in ijson.items(f, "item"): process_item(item)
-
统信UOS文件监控:
from watchdog.observers.inotify import InotifyObserver def watch_config_changes(): observer = InotifyObserver() observer.schedule( ConfigHandler(), path=get_storage_path()['json'], recursive=False ) observer.start()
关键问题解决方案
-
统信UOS权限问题:
# 在应用.desktop文件中声明需要的数据目录 X-UOS-Data-Path=~/.local/share/yourapp
-
数据库锁定问题:
# 使用WAL模式+重试机制 def get_connection_with_retry(max_retries=3): for i in range(max_retries): try: return sqlite3.connect(db_path, timeout=10) except sqlite3.OperationalError: if i == max_retries - 1: raise time.sleep(0.1)
-
中文路径处理:
# 统信UOS下确保使用UTF-8编码 path = path.encode('utf-8').decode('utf-8') with open(path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False)
通过以上实现,您的Kivy应用可以在统信UOS上实现安全可靠的本地数据存储,同时兼顾性能和用户体验。