PySide开发MySql远程备份工具

MySql数据库安装在机房,而工作人员日常办公的地方距离机房有段距离,且不在同一楼层。出入机房不是很方便。就想着能否给这些人员开发一个图形化的备份MySql数据库的小工具?
使用组件如下:
(1)Python
(2)PySide
(3)mysqldump
其实mysql已经提供了一个mysqldump.exe来做mysql数据库的备份,也支持远程操作,但因为是命令行形式的,对于普通的工作人员来说使用起来就非常不方便了,这个小工具的原理就是使用PySide对mysqldump.exe做一封装,提供GUI接口。
里面值得注意的是Thread和subprocess的结合,具体详见如下代码:

ContractedBlock.gifExpandedBlockStart.gifView Code
########################################################################
class BackupThread(QThread):
"""备份数据库线程"""
dataReady
= Signal(object)
config
= ApplicationConfig()
#----------------------------------------------------------------------
def run(self):
"""具体执行部分"""
self.dataReady.emit(u
"正在执行,请稍后......")
#加载配置信息
self.config.load()
#组织备份数据库所需要的命令
filestamp= time.strftime("%Y-%m-%d")

filename
= "%s-%s.sql" % (self.config.databasename, filestamp)
filename
= os.path.join(self.config.backupdir, filename)
mysqldumpfile
= os.path.join(os.getcwd(), "mysqldump.exe")
command
= "%s -u %s -p%s -h %s -e --opt -c %s" % (mysqldumpfile, self.config.user, self.config.password, self.config.remoteIp, self.config.databasename)
print command
pipe
= subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
#print pipe.stdout.readlines()
#promptMsg= "".join(pipe.stdout.readlines())
#print "promptMsg is:", promptMsg
fp= open(filename, "w")
item
= None
for line in pipe.stdout:
fp.writelines(line)
self.dataReady.emit(line)
fp.close()
completeMsg
= "";
#取出最后一个item,判断里面的内容是否包含
if item is not None:
text
= item.text()
if text.find("Dump completed") > 0:
print "Completed"
completeMsg
= u"开始压缩,请稍后......"
#计算压缩后的文件名
compressedfilename= os.path.splittext(filename)[0] + ".zip"
if self.compress(filename, compressedfilename):
completeMsg
= u"压缩文件出错,请检查!"
else:
completeMsg
= u"操作已完成,请检查!"
else:
completeMsg
= u"操作过程中出现错误,请检查!"
else:
completeMsg
= u"操作过程中出现错误,请检查!"

self.dataReady.emit(completeMsg)

全部代码如下所示:
(1)ApplicationConfig.py

ContractedBlock.gifExpandedBlockStart.gifView Code
#-*-coding:utf-8-*-

import ConfigParser


########################################################################
class ApplicationConfig:
"""
程序相关配置信息
"""

#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
self.remoteIp
= "127.0.0.1"
self.remotePort
= "3306"
self.user
= "root"
self.password
= ""
self.databasename
= ""
self.backupdir
= "c:\\"
self.config
= ConfigParser.ConfigParser()

#----------------------------------------------------------------------
def load(self):
"""
加载配置信息
"""
try:
self.config.read(r
".\ApplicationConfig.cfg")
self.remoteIp
= self.config.get("mysql", "remoteip")
self.remotePort
= self.config.get("mysql", "remoteport")
self.user
= self.config.get("mysql", "user")
self.password
= self.config.get("mysql", "password")
self.databasename
= self.config.get("mysql", "databasename")
self.backupdir
= self.config.get("mysql", "backupdir")
except Exception as ex:
print "Some exception occured when invoke load(), exception message is ", ex, " please check it !"

#----------------------------------------------------------------------
def save(self):
"""
保存配置信息
"""
self.config.read(r
".\ApplicationConfig.cfg")
if "mysql" not in self.config.sections():
self.config.add_section(
"mysql")
self.config.set(
"mysql", "remoteip", self.remoteIp)
self.config.set(
"mysql", "remoteport", self.remotePort)
self.config.set(
"mysql", "user", self.user)
self.config.set(
"mysql", "password", self.password)
self.config.set(
"mysql", "databasename", self.databasename)
self.config.set(
"mysql", "backupdir", self.backupdir)
fp
= open(r".\ApplicationConfig.cfg", "w")
self.config.write(fp)
#----------------------------------------------------------------------
def __str__(self):
"""
返回相应的字符串表示
"""
description
= "remoteip : \t" + self.remoteIp + "\n" + \
"user : \t" + self.user + "\n" +\
"password : \t"+ self.password+ "\n"+ \
"databasename \t" + self.databasename + "\n" + \
"backupdir : \t" + self.backupdir + "\n"
return description
(2)MainForm.py
ContractedBlock.gifExpandedBlockStart.gifView Code
# -*- coding: utf-8 -*-

import sys
reload(sys)
sys.setdefaultencoding(
'utf-8')

from PySide.QtCore import *
from PySide.QtGui import *
import os
import time
import subprocess
import zipfile


from ApplicationConfig import ApplicationConfig

class ConfigurationPage(QWidget):
def __init__(self, parent=None):
super(ConfigurationPage, self).
__init__(parent)
self.configGroup
= QGroupBox(u"相关配置信息")

self.remoteIPLabel
= QLabel(u"数据库所在IP地址:")
self.editRemoteIP
= QLineEdit(u"数据库所在IP地址")
self.remotePortLabel
= QLabel(u"使用端口:")
self.editPort
= QLineEdit(u"使用端口")
self.userLabel
= QLabel(u"用户名:")
self.editUser
= QLineEdit(u"用户名")
self.passwordLabel
= QLabel(u"密码:")
self.editPassword
= QLineEdit(u"密码")
self.dabasenameLabel
= QLabel(u"数据库名:")
self.editDatabaseName
= QLineEdit(u"数据库名")
self.backupdirLabel
= QLabel(u"备份文件存放目录:")
self.editBackupDir
= QLineEdit(u"备份文件存放目录")
self.browseButton
= QPushButton(u"浏览")
self.browseButton.clicked.connect(self.onBrowse)

self.paremeterLayout
= QGridLayout();
self.paremeterLayout.addWidget(self.remoteIPLabel, 0, 0)
self.paremeterLayout.addWidget(self.editRemoteIP, 0,
1, 1, 2)
self.paremeterLayout.addWidget(self.remotePortLabel,
1, 0)
self.paremeterLayout.addWidget(self.editPort,
1, 1, 1, 2)
self.paremeterLayout.addWidget(self.userLabel,
2, 0)
self.paremeterLayout.addWidget(self.editUser,
2, 1, 1, 2)
self.paremeterLayout.addWidget(self.passwordLabel,
3, 0)
self.paremeterLayout.addWidget(self.editPassword,
3, 1, 1, 2)
self.paremeterLayout.addWidget(self.dabasenameLabel,
4, 0)
self.paremeterLayout.addWidget(self.editDatabaseName,
4, 1, 1, 2)
self.paremeterLayout.addWidget(self.backupdirLabel,
5, 0)
self.paremeterLayout.addWidget(self.editBackupDir,
5, 1)
self.paremeterLayout.addWidget(self.browseButton,
5, 2)

self.btnSave
= QPushButton(u"保存")
self.btnSave.setMinimumHeight(
50)
self.btnSave.clicked.connect(self.onSave)

self.configGroup.setLayout(self.paremeterLayout)

self.mainLayout
= QVBoxLayout()
self.mainLayout.addWidget(self.configGroup)
self.mainLayout.addSpacing(
20)
self.mainLayout.addWidget(self.btnSave)
self.mainLayout.addStretch(
1)

self.setLayout(self.mainLayout)

self.config
= ApplicationConfig()
self.doInitialize()
#----------------------------------------------------------------------
def onSave(self):
"""保存处理"""
try:
self.config.remoteIp
= self.editRemoteIP.text()
self.config.remotePort
= self.editPort.text()
self.config.user
= self.editUser.text()
self.config.password
= self.editPassword.text()
self.config.databasename
= self.editDatabaseName.text()
self.config.backupdir
= self.editBackupDir.text()
self.config.save()
except:
print "some exceptions occured when invoke onSave() method, please check it!"
#print unicode(self.config.remoteIp)
#----------------------------------------------------------------------
def onBrowse(self):
"""选择目录"""
directory
= QFileDialog.getExistingDirectory(self, u"查找备份目录",
QDir.currentPath())
if directory:
self.editBackupDir.setText(directory)

#----------------------------------------------------------------------
def doInitialize(self):
"""初始化相关参数"""
self.config.load()
self.editRemoteIP.setText(unicode(self.config.remoteIp))
self.editPort.setText(unicode(self.config.remotePort))
self.editUser.setText(unicode(self.config.user))
self.editPassword.setText(unicode(self.config.password))
self.editDatabaseName.setText(unicode(self.config.databasename))
self.editBackupDir.setText(unicode(self.config.backupdir))


########################################################################
class BackupThread(QThread):
"""备份数据库线程"""
dataReady
= Signal(object)
config
= ApplicationConfig()
#----------------------------------------------------------------------
def run(self):
"""具体执行部分"""
self.dataReady.emit(u
"正在执行,请稍后......")
#加载配置信息
self.config.load()
#组织备份数据库所需要的命令
filestamp= time.strftime("%Y-%m-%d")

filename
= "%s-%s.sql" % (self.config.databasename, filestamp)
filename
= os.path.join(self.config.backupdir, filename)
mysqldumpfile
= os.path.join(os.getcwd(), "mysqldump.exe")
command
= "%s -u %s -p%s -h %s -e --opt -c %s" % (mysqldumpfile, self.config.user, self.config.password, self.config.remoteIp, self.config.databasename)
print command
pipe
= subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
#print pipe.stdout.readlines()
#promptMsg= "".join(pipe.stdout.readlines())
#print "promptMsg is:", promptMsg
fp= open(filename, "w")
item
= None
for line in pipe.stdout:
fp.writelines(line)
self.dataReady.emit(line)
fp.close()
completeMsg
= "";
#取出最后一个item,判断里面的内容是否包含
if item is not None:
text
= item.text()
if text.find("Dump completed") > 0:
print "Completed"
completeMsg
= u"开始压缩,请稍后......"
#计算压缩后的文件名
compressedfilename= os.path.splittext(filename)[0] + ".zip"
if self.compress(filename, compressedfilename):
completeMsg
= u"压缩文件出错,请检查!"
else:
completeMsg
= u"操作已完成,请检查!"
else:
completeMsg
= u"操作过程中出现错误,请检查!"
else:
completeMsg
= u"操作过程中出现错误,请检查!"

self.dataReady.emit(completeMsg)

########################################################################
class BackupPage(QWidget):
""""""

#----------------------------------------------------------------------
def __init__(self, parent=None):
"""Constructor"""
super(BackupPage, self).
__init__(parent)
self.backupButton
= QPushButton(u"备份数据库")
self.backupButton.setMinimumHeight(
50)
self.backupButton.clicked.connect(self.doBackupOperation)
self.labelPrompt
= QLabel(u"提示信息") #执行结果显示
self.listPrompt = QListWidget()
self.labelPrompt.setWordWrap(True)
self.layout
= QVBoxLayout()
self.layout.addStretch()
self.layout.addWidget(self.backupButton)
#self.layout.addSpacing(20)
self.layout.addWidget(self.labelPrompt)
self.layout.addWidget(self.listPrompt)
self.layout.addStretch()
self.config
= ApplicationConfig()
self.thread
= BackupThread() #备份线程
self.thread.dataReady.connect(self.updateUI, Qt.QueuedConnection)
self.setLayout(self.layout)
#----------------------------------------------------------------------
def doBackupOperation(self):
"""执行备份数据库的任务"""
#self.labelPrompt.setText(u"正在执行,请稍后......")
##加载配置信息
#self.config.load()
##组织备份数据库所需要的命令
#filestamp= time.strftime("%Y-%m-%d")

#filename = "%s-%s.sql" % (self.config.databasename, filestamp)
#filename = os.path.join(self.config.backupdir, filename)
#mysqldumpfile = os.path.join(os.getcwd(), "mysqldump.exe")
#command= "%s -u %s -p%s -h %s -e --opt -c %s" % (mysqldumpfile, self.config.user, self.config.password, self.config.remoteIp, self.config.databasename)
#print command
#pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
#fp= open(filename, "w")
#item = None
#for line in pipe.stdout:
#fp.writelines(line)
#item = QListWidgetItem(line)
#self.listPrompt.addItem(item)
#if self.listPrompt.count() > 0:
#self.listPrompt.setCurrentRow(self.listPrompt.count() - 1)
#pass
#fp.close()
#self.listPrompt.setFocus()
#completeMsg= "";
##取出最后一个item,判断里面的内容是否包含
#if item is not None:
#text= item.text()
#if text.find("Dump completed") > 0:
#print "Completed"
#completeMsg = u"开始压缩,请稍后......"
##计算压缩后的文件名
#compressedfilename= os.path.splittext(filename)[0] + ".zip"
#if self.compress(filename, compressedfilename):
#completeMsg = u"压缩文件出错,请检查!"
#else:
#completeMsg = u"操作已完成,请检查!"
#else:
#completeMsg = u"操作过程中出现错误,请检查!"
#else:
#completeMsg = u"操作过程中出现错误,请检查!"
#self.labelPrompt.setText(completeMsg)

self.thread.start()
#启动线程
#----------------------------------------------------------------------
def updateUI(self, data):
"""更新UI部分处理"""
item
= QListWidgetItem(data)
self.listPrompt.addItem(data)
self.listPrompt.setFocus()
#----------------------------------------------------------------------
def compress(self, infilename, dstfilename, level = 9):
"""压缩"""
result
= False;
try:
zfile
= zipfile.ZipFile(dstfilename, "w")
zfile.write(infilename, os.path.split(infilename)[
1])
zfile.close()
result
= True
except:
print "some error occured when invoke (), please check it!"
result
= False

return result;


########################################################################
class HelpPage(QWidget):
""""""

#----------------------------------------------------------------------
def __init__(self, parent=None):
"""Constructor"""
super(HelpPage, self).
__init__(parent)
self.helpLabel
= QLabel(u"使用说明:\n\t"
u
"(1)备份数据前请检查相关配置信息是否正确\n\t"
u
"(2)点击备份数据库按钮,等待本分操作完成\n\t"
u
"(3)请留意备份过程中是否有错误信息\n\t")

self.layout
= QVBoxLayout()
self.layout.addSpacing(
10)
self.layout.addWidget(self.helpLabel)
self.layout.addStretch(
1)

self.setLayout(self.layout)

class MainDialog(QDialog):
#----------------------------------------------------------------------
def __init__(self, parent=None):
"""初始化函数
"""
super(MainDialog, self).
__init__(parent)

#Create Widgets

self.contentsWidget
= QListWidget()
self.contentsWidget.setViewMode(QListView.IconMode)
self.contentsWidget.setIconSize(QSize(
96, 84))
self.contentsWidget.setMovement(QListView.Static)
self.contentsWidget.setMaximumWidth(
128 + 10)
self.contentsWidget.setMinimumHeight((
84 + 12 ) * 4)
self.contentsWidget.setSpacing(
12)

self.pagesWidget
= QStackedWidget()
self.pagesWidget.addWidget(ConfigurationPage())
self.pagesWidget.addWidget(BackupPage())
self.pagesWidget.addWidget(HelpPage())

self.closeButton
= QPushButton(u"退出")

self.createIcons()
self.contentsWidget.setCurrentRow(0)

self.closeButton.clicked.connect(self.close)

self.horizontalLayout
= QHBoxLayout()
self.horizontalLayout.addWidget(self.contentsWidget)
self.horizontalLayout.addWidget(self.pagesWidget,
1)

self.buttonsLayout
= QHBoxLayout()
self.buttonsLayout.addStretch(
1)
self.buttonsLayout.addWidget(self.closeButton)

self.mainLayout
= QVBoxLayout()
self.mainLayout.addLayout(self.horizontalLayout)
self.mainLayout.addSpacing(
12)
self.mainLayout.addLayout(self.buttonsLayout)

self.setLayout(self.mainLayout)

#Add button
self.setWindowTitle(u"数据库备份")

def changePage(self, current, previous):
if not current:
current
= previous

self.pagesWidget.setCurrentIndex(self.contentsWidget.row(current))

def createIcons(self):
configButton
= QListWidgetItem(self.contentsWidget)
configButton.setIcon(QIcon(
'./images/config.png'))
configButton.setText(u
"相关配置信息")
configButton.setTextAlignment(Qt.AlignHCenter)
configButton.setFlags(Qt.ItemIsSelectable
| Qt.ItemIsEnabled)

updateButton
= QListWidgetItem(self.contentsWidget)
updateButton.setIcon(QIcon(
'./images/update.png'))
updateButton.setText(u
"备份")
updateButton.setTextAlignment(Qt.AlignHCenter)
updateButton.setFlags(Qt.ItemIsSelectable
| Qt.ItemIsEnabled)

queryButton
= QListWidgetItem(self.contentsWidget)
queryButton.setIcon(QIcon(
'./images/query.png'))
queryButton.setText(u
"使用说明")
queryButton.setTextAlignment(Qt.AlignHCenter)
queryButton.setFlags(Qt.ItemIsSelectable
| Qt.ItemIsEnabled)

self.contentsWidget.currentItemChanged.connect(self.changePage)

if __name__ == "__main__":
app
= QApplication(sys.argv)
form
= MainDialog()
form.show()
sys.exit(app.exec_())
(3)配置文件ApplicationConfig.cfg
ContractedBlock.gifExpandedBlockStart.gifView Code
[mysql]
remoteport
= 3306
remoteip
= 10.88.81.96
databasename
= test
password
= root
backupdir
= E:/Study/Python/MySqlAssistant
user
= root
执行MainForm.py即可
如果要编译成exe,可采用py2exe,或者cx_freeze进行编译

转载于:https://www.cnblogs.com/Jerryshome/archive/2011/05/10/2042136.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/378440.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HadoopSourceAnalyse --- Nodemanager Container request handler

Overview Container 是Hadoop中运行任务的地方,当Resourcemanager收到一任务请求后,会向nodemanager 请求一个Container 来运行ApplicationMaster, ApplicationMaster运行起来之后,会继续向Resourcemanager请求新的container来运行…

数据结构 二叉树的存储结构_线程二叉树| 数据结构

数据结构 二叉树的存储结构线程二叉树 (Threaded Binary Tree ) A binary tree can be represented by using array representation or linked list representation. When a binary tree is represented using linked list representation. If any node is not having a child …

八、关于防水透湿整理

1,防水透湿整理加工技术的类型? 收集资料阶段 按照加工方式分类 防水透湿织物按照加工方式可分为高密织物、涂层织物和层压织物。不同加工方式所对应的织物各有特色。高密织物产生于 20 世纪 80 年代,它的密度可达到普通织物的 20 倍。在晴朗天气时,纱线孔隙大约为 10 μm…

求质数算法的N种境界 (N 10) zz

★引子 前天,俺在《俺的招聘经验[4]:通过笔试答题能看出啥?》一文,以"求质数"作为例子,介绍了一些考察应聘者的经验。由于本文没有政治敏感内容,顺便就转贴到俺在CSDN的镜像博客。   昨天&…

Python匿名函数---排序

一、列表的排序 nums [1,2,3,5,4,7,87,4,9,56,44,7,5] nums.sort()#默认从小到大排序 nums#结果为:[1, 2, 3, 4, 4, 5, 5, 7, 7, 9, 44, 56, 87]nums [1,2,3,5,4,7,87,4,9,56,44,7,5] nums.sort(reverseTrue)#从大到小排序 nums#结果为:[87, 56, 44, …

linux下怎么查kill某个进程,Linux下查询进程PS或者杀死进程kill的小技巧

假设我们要kill掉tomcat:那么我们首先需要tomcat的进程号pid:ps -aux | grep tomcat记下tomcat的PID后,执行:kill PID(tomcat)好了,就到这里....路人甲:小的们,灭了这个欺骗人民情感的家伙&…

opencv模板匹配

matchTemplate函数参数 模板匹配是通过模板在采集到的原图像进行滑动寻找与模板图像相似的目标。模板匹配不是基于直方图的方式,而是基于图像的灰度匹配。 6种匹配度量方法: 平方差匹配法CV_TM_SQDIFF 归一化平方差匹配法CV_TM_SQDIFF_NORMED 相关匹配…

Java程序设计4——集合类

1 JAVA集合概述 Java集合封装了一系列数据结构比如链表、二叉树、栈、队列等,然后提供了针对这些数据结构的一系列算法比如查找、排序、替换,使编程难度大大降低。(这句话有可能是非法…

python与tensorflow知识点截图集锦(持续囤积)

目录前言conda环境管理python语法【1】语言属性【2】代码缩进问题【3】input和output函数与print函数【4】关键字与简单数据类型与简单运算符【5】利用缩进体现逻辑关系【6】数据结构:列表与元组【7】数据结构:字典【8】数据结构:集合【8】基…

linux测试固态硬盘读写速度,在 Linux 上检测 IDE/SATA SSD 硬盘的传输速度

你知道你的硬盘在 Linux 下传输有多快吗?不打开电脑的机箱或者机柜,你知道它运行在 SATA I (150 MB/s) 、 SATA II (300 MB/s) 还是 SATA III (6.0Gb/s) 呢?你能够使用 hdparm 和 dd 命令来检测你的硬盘速度。它为各种硬盘的 ioctls 提供了命…

Opencv——批量处理同一文件夹下的图片(解决savedfilename = dest + filenames[i].substr(len)问题)

文章目录前言一、完整代码二、实现效果前言 第一份代码实现了批量修改同一文件夹下图片的尺寸,有其他需求时仅需修改处理部分的代码以及文件夹路径。 第二份代码实现了批量截取同一文件夹下每张图片的ROI区域作为结果保存,注意截取后按下enter键才会跳到…

处理文件、摄像头和图形用户界面

1、基本I/O脚本 1.1 读/写图像文件 import numpy import cv2#利用二维Numpy数组简单创建一个黑色的正方形图像 img numpy.zeros((3,3),dtypenumpy.uint8) img #结果为:array([[0, 0, 0],[0, 0, 0],[0, 0, 0]], dtypeuint8)img.shape#结果为:(3, 3)###…

linux桌面天气,Ubuntu 14.10中安装和配置天气应用

对于操作系统平台而言,有各种小插件功能方便用户日常应用。在Ubuntu桌面中提供天气信息的功能,可以使用Unity Dash和桌面应用来获得相关信息,比如Typhoon。但对于用户而言,可以提供快速查询天气状况和温度数据,并且只需…

linux批处理操作系统_批处理操作系统

linux批处理操作系统批处理操作系统 (Batch Processing Operating System) When we are working in an environment there is a restriction of making use of computer resources effectively and improvement in the programmers output. When we are working with tapes a l…

STL容器及其简单应用(stack、priority_queue、vector、deuqe、list、map/multimap、set/multiset)

目录前言【1】stack操作以及应用stack的几个核心接口利用stack完成进制转换【2】priority_queue操作以及应用priority_queue的几个核心接口利用priority_queue完成合并果子问题【3】vector操作以及应用vector的几个核心接口利用vector完成随机排序【4】deuqe(双向队列)操作以及…

已知一个掺杂了多个数字字符的中文名拼音,去掉所有数字字符之后,形式为“名”+空格+“姓”;并且名和姓的首字母大写,其他小写,要求输出姓名全拼,且全为小写。(后附详细样例说明)

已知一个掺杂了多个数字字符的中文名拼音,去掉所有数字字符之后,形式为“名”空格“姓”;并且名和姓的首字母大写,其他小写,要求输出姓名全拼,且全为小写。(后附详细样例说明) 【输入…

在一个风景秀丽的小镇,一天早上,有N名晨跑爱好者(编号1~N)沿着优雅的江边景观道朝同一方向进行晨跑

【问题描述】 在一个风景秀丽的小镇,一天早上,有N名晨跑爱好者(编号1~N)沿着优雅的江边景观道朝同一方向进行晨跑,第i名跑者从位置si处起跑,且其速度为Vi。换句话说,对所有的实数t≥0,在时刻t时第i名跑者的…

linux内核测试,Linux内核测试的生命周期

内核持续集成(CKI)项目旨在防止错误进入 Linux 内核。在 Linux 内核的持续集成测试 一文中,我介绍了 内核持续集成Continuous Kernel Integration(CKI)项目及其使命:改变内核开发人员和维护人员的工作方式。本文深入探讨了该项目的某些技术方面&#xff…

【视觉项目】【day3】8.22号实验记录(利用canny检测之后的来进行模板匹配)

【day3】8.22号实验记录(几乎没干正事的一天,利用canny检测之后的来进行模板匹配) 今天没搞代码,主要是问研究生学长工业摄像头的接法的,学长也不知道,明天问问老师。。。 晚上搞了一下canny之后的模板匹配…

linux dd 大文件下载,Linux dd+grep 大文件二分查找

Linux dd 命令用于读取、转换并输出数据。dd 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。参数说明(dd --help)Usage: dd [OPERAND]...or: dd OPTIONCopy a file, converting and formatting according to th…