1. 程式人生 > >Qt資料庫之資料庫常用操作

Qt資料庫之資料庫常用操作

前面的章節介紹了怎麼使用 Qt 連線訪問資料庫 SQLite 和 MySQL,在這一節裡將介紹訪問資料庫的常用操作細節,主要是關於QSqlDatabaseQSqlQuery 的運用,以及資料庫訪問安全相關的SQL 注入攻擊

小提示
1. 現在比較推薦資料庫設計時每個表都有一個無意義的主鍵,如 id
2. 儘量不使用外來鍵,資料的邏輯關係使用上面提到的無意義的 id 來關聯,這樣的好處是資料遷移的時候不需要考慮外來鍵的因素而造成很多麻煩。資料的邏輯關係由程式來控制。
3. 因為沒有用外來鍵而不能級連刪除,如果擔心資料庫裡會留下一些垃圾資料,可以用定時任務在系統負載比較輕的時候刪除它們,例如晚上 3 點。
4

. 如果時間需要根據不同的時區顯示,時間相關的欄位最好使用 timestamp 而不是 datetime。例如開發一個會議相關的軟體,同時有中國,美國,德國人蔘加會議,如果大家看到開會時間是 2015-03-03 10:00:00,每個人都會自然的認為是自己當地的時間,那麼開會的時候就只有你自己一個人了。

準備資料

在開始講解之前,我們先來準備好需要用到的資料。建立資料庫 qt,然後在此資料庫裡建立 3 張表 user,blog,comment,以及在每一張表裡插入一些資料,細節如下。

建立 user 表

CREATE TABLE `user` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(256) NOT NULL, `password` varchar(256) NOT NULL, `email` varchar(256) DEFAULT NULL, `mobile` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) ) INSERT INTO `user` (`id`, `username`, `password`, `email`, `mobile`) VALUES (1, 'Alice', 'passw0rd', NULL, NULL), (2, 'Bob'
, 'Passw0rd', NULL, NULL), (3, 'Josh', 'Pa88w0rd', NULL, NULL);
id username password email mobile
1 Alice passw0rd NULL NULL
2 Bob Passw0rd NULL NULL
3 Josh Pa88w0rd NULL NULL

建立 blog 表

CREATE TABLE `blog` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `user_id` int(11) NOT NULL,
    `content` text NOT NULL,
    `created_time` datetime NOT NULL,
    `last_updated_time` datetime NOT NULL,
    PRIMARY KEY (`id`)
)

INSERT INTO `blog` (`id`, `user_id`, `content`, `created_time`, `last_updated_time`) VALUES
(1, 1, 'Content of blog 1.', '2015-01-01 10:10:10', '2015-01-01 10:10:10'),
(2, 2, 'Content of blog 2.', '2015-02-02 20:20:20', '2015-02-02 20:20:20');
id user_id content created_time last_updated_time
1 1 Content of blog 1. 2015-01-01 10:10:10 2015-01-01 10:10:10
2 2 Content of blog 2. 2015-02-02 20:20:20 2015-02-02 20:20:20

建立 comment 表

CREATE TABLE `comment` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `user_id` int(11) NOT NULL,
    `blog_id` int(11) NOT NULL,
    `content` text NOT NULL,
    `created_time` datetime NOT NULL,
    PRIMARY KEY (`id`)
)

INSERT INTO `comment` (`id`, `user_id`, `blog_id`, `content`, `created_time`) VALUES
(1, 1, 1, 'Very useful.', '2015-01-02 11:11:11'),
(2, 3, 2, 'Super', '2015-03-03 23:33:33');
id user_id blog_id content created_time
1 1 1 Very useful. 2015-01-02 11:11:11
2 3 2 Super 2015-03-03 23:33:33

QSqlDatabase

訪問資料庫前必須先和資料庫建立連線,Qt 裡用 QSqlDatabase 表示一個數據庫的連線(有點不習慣,既然表示的是連線,有沒有覺得如果叫 QSqlConnection 會更好?可惜 Qt 不是我們設計的!),每個連線都有自己的名字 connectionName,用同一個 connectionName 得取的 QSqlDatabase 物件都是表示同一個連線。有一點需要注意,如果要在多執行緒裡訪問資料庫,每個執行緒都要使用不同的資料庫連線,即每個執行緒使用的 QSqlDatabase 的 connectionName 都不一樣,否則可能會遇到很多預料不到的事。

建立 QSqlDatabase 物件用靜態函式 QSqlDatabase QSqlDatabase::​addDatabase(const QString &type, const QString &connectionName=QLatin1String(defaultConnection))。第一個引數 type 是指定資料庫的型別,例如"QSQLITE""QMYSQL""QPSQL"。第二個引數是 connectionName,可以是任意的字串,預設是"qt_sql_default_connection" 而不是空字串。

獲取 QSqlDatabase 物件用靜態函式 QSqlDatabase QSqlDatabase::​database(const QString &connectionName=QLatin1String(defaultConnection), bool open=true)

使用預設的 connectionName 建立和獲取連線:

void createDefaultConnection() {
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");
    db.setHostName("127.0.0.1");
    db.setDatabaseName("qt"); // 如果是 SQLite 則為資料庫檔名
    db.setUserName("root");   // 如果是 SQLite 不需要
    db.setPassword("root");   // 如果是 SQLite 不需要

    if (!db.open()) {
        qDebug() << "Connect to MySql error: " << db.lastError().text();
        return;
    }
}

QSqlDatabase getDefaultConnection() {
    return QSqlDatabase::database();
}
  1. 我們不提供 connectName,則 Qt 使用預設的 connectName "qt_sql_default_connection"
  2. 呼叫 createDefaultConnection() 建立資料庫連線
  3. 呼叫 getConnectionByName() 取得資料庫連線,多次呼叫這條語句得到的都是同一個資料庫連線

使用自定義 connectionName 建立和獲取連線:

void createConnectionByName(const QString &connectionName) {
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", connectionName);
    db.setHostName("127.0.0.1");
    db.setDatabaseName("qt"); // 如果是 SQLite 則為資料庫檔名
    db.setUserName("root");   // 如果是 SQLite 不需要
    db.setPassword("root");   // 如果是 SQLite 不需要

    if (!db.open()) {
        qDebug() << "Connect to MySql error: " << db.lastError().text();
        return;
    }
}

QSqlDatabase getConnectionByName(const QString &connectionName) {
    return QSqlDatabase::database(connectionName);
}
  1. 例如 connectName 為 MyConnection
  2. 呼叫 createConnectionByName(MyConnection) 建立資料庫連線
  3. 呼叫 getConnectionByName(MyConnection) 取得資料庫連線,多次呼叫這條語句得到的都是同一個資料庫連線

重複使用同一個 connectionName 建立資料庫連線並不會建立多個同名的連線,也不會發生錯誤,只是會刪除已經存在的連線,然後用此 connectionName 重新建立連線。這是很有用的,例如資料庫是安裝在其他電腦上,程式開始執行的時候資料庫連線是好用的,但是過了一會網路出問題導致資料庫連線斷開了,過一會網路恢復了,用這個資料庫連線就訪問不了資料庫了,這時還是使用同一個 connectionName 再次建立資料庫連線,就可以訪問資料庫了。但是不要因為使用同一個 connectionName 建立資料庫連線不會導致程式出錯,為了防止上面的情況於是每次使用資料庫連線的時候就重新建立一個。建立資料庫連線是一個非常耗費資源和時間的操作,底層是 Socket 連線,這樣做雖然保證了程式的正確性,但卻是以效率為代價換回來的,並不是理想的方案。

以前一直擔心在函式之間傳遞 QSqlDatabase 的棧物件而不是指標或者引用會不會佔用很多棧空間,也有可能會不會由於呼叫它的複製建構函式而生成另一個 QSqlDatabase 物件導致什麼問題?首先sizeof(QSqlDatabase) 輸出 8,說明 QSqlDatabase 佔用 8 個位元組,開啟 QSqlDatabase 的原始碼也可以看到它只有 2 個指標的成員變數char *defaultConnection 和 QSqlDatabasePrivate *d,所以 QSqlDatabase 佔用的空間不大。其次,它的複製建構函式建立的新物件和原來的物件共享char *defaultConnection 和 QSqlDatabasePrivate *d,所以可以放心的在函式之間傳遞 QSqlDatabase 物件而不用擔心出什麼問題。

QSqlQuery

QSqlQuery 有兩個重要的建構函式,平時我們也基本上就用這兩種形式來構造 QSqlQuery 物件。

QSqlQuery::​QSqlQuery(const QString &query = QString(), QSqlDatabase db = QSqlDatabase()):如果沒有傳入或者傳入一個無效的 QSqlDatabase 物件,則使用預設的 QSqlDatabase;如果 query 不是空字串,則會執行這個 query 的資料庫操作。例如QSqlQuery query("SELECT * FROM user") 則就會使用預設的資料庫連線執行查詢操作,而 QSqlQuery query 則會使用預設的資料庫連線建立一個 QSqlQuery 物件,但是不執行任何操作。

QSqlQuery::​QSqlQuery(QSqlDatabase db):使用指定的資料庫連線建立 QSqlQuery 物件,如果資料庫連線無效,則使用預設的資料庫連線,例如QSqlQuery query(getConnectionByName("MyConnection"))

查詢操作

已經有了資料庫和相關資料,瞭解了 QSqlDatabase 和 QSqlQuery,接下來舉例分析使用 QSqlQuery,可能遇到的問題以及解決辦法。為了簡單起見,都使用預設的資料庫連線,思考一下下面的例子裡怎麼把預設的資料庫連線換成我們自己指定的 connectionName 的連線呢?

1. 輸出 user 表裡所有的 id, username, password

/**
 * 輸出 user 表裡所有的 id, username, password
 */
void outputIdUsernamePassword() {
    QSqlQuery query("SELECT id, username, password FROM user");

    while (query.next()) {
        qDebug() << QString("Id: %1, Username: %2, Password: %3")
                    .arg(query.value("id").toInt())
                    .arg(query.value("username").toString())
                    .arg(query.value("password").toString());
    }
}

輸出:

Id: 1, Username: Alice, Password: passw0rd
Id: 2, Username: Bob, Password: Passw0rd
Id: 3, Username: Josh, Password: Pa88w0rd

2. 輸出 username 為 Alice 的 user

1. 函式定義
/**
 * 輸出 user 其 username 等於傳入的引數 username
 * @param username
 */
void outputUser(const QString &username) {
    QString sql = "SELECT * FROM user WHERE username='" + username + "'";
    QSqlQuery query(sql);

    while (query.next()) {
        qDebug() << QString("Id: %1, Username: %2, Password: %3")
                    .arg(query.value("id").toInt())
                    .arg(query.value("username").toString())
                    .arg(query.value("password").toString());
    }
}

2. 函式呼叫
outputUser("Alice");

輸出:

Id: 1, Username: Alice, Password: passw0rd

輸出結果和我們期待的一樣。但是思考一下,上面的程式有沒有什麼問題?
如果我們這麼呼叫函式 outputUser("Alice' OR '1=1"),輸出如下:

Id: 1, Username: Alice, Password: passw0rd
Id: 2, Username: Bob, Password: Passw0rd
Id: 3, Username: Josh, Password: Pa88w0rd

是不是有什麼不對?outputUser("Alice' OR '1=1") 按我們的想法應該輸出 username 等於 Alice' OR '1=1 的記錄,但卻輸出了 user 表裡的所有記錄,完全和期望的不一樣,一定是有什麼地方出錯了,但是看上去都沒什麼問題呀,怎麼都找不到錯誤吧

這裡我們引入一個概念叫做 SQL 注入攻擊

SQL 注入攻擊指的是通過構建特殊的輸入作為引數傳入,而這些輸入大都是 SQL 語法裡的一些組合,通過執行 SQL 語句進而執行攻擊者所要的操作,其主要原因是程式沒有細緻地過濾使用者輸入的資料,致使非法資料侵入系統。

上面的程式在查詢一個使用者的時候卻輸出了所有使用者的資訊,就是一個 SQL 注入攻擊的例子,原因是使用的 SQL 語句是用字串相加拼湊出來的,以至於引數中的特殊字元' 沒有被轉義而拼成了 SELECT * FROM user WHERE username='Alice' OR '1=1',WHERE 條件裡有OR '1=1',所以條件永遠為真,於是輸出了所有的記錄,這樣做是很危險的,如果因此而洩漏了公司機密資訊,都不敢往下想了。

3. 怎麼避免SQL 注入攻擊呢?

使用 Prepared Query 可以避免SQL 注入攻擊

/**
 * 輸出 user 其 username 等於傳入的引數 username
 * @param username
 */
void outputUserWithPreparedQuery(const QString &username) {
    QString sql = "SELECT * FROM user WHERE username=:username";
    QSqlQuery query;    // [1] 可以傳入資料庫連線,但是不能傳入 SQL 語句
    query.prepare(sql); // [2] 宣告使用 prepqred 的方式解析 SQL 語句

    query.bindValue(":username", username); // [3] 把佔位符替換為傳入的引數
    query.exec(); // [4] 執行資料庫操作

    while (query.next()) { // [5]
        qDebug() << QString("Id: %1, Username: %2, Password: %3")
                    .arg(query.value("id").toInt())
                    .arg(query.value("username").toString())
                    .arg(query.value("password").toString());
    }
}

呼叫 outputUserWithPreparedQuery("Alice") 輸出:

Id: 1, Username: Alice, Password: passw0rd

呼叫 outputUserWithPreparedQuery("Alice' OR '1=1") 則沒有輸出,因為 user 表裡沒有 username 為Alice' OR '1=1 的記錄。太好了,SQL 注入攻擊的問題很容易就解決了。

使用 Prepared Query 分為以下 5 步:
  1. 建立 QSqlQuery 物件:QSqlQuery query;
  2. 呼叫 query.prepare(sql); 宣告要使用 Prepared Query 的方式來解析 SQL 語句
  3. 呼叫 bindValue() 函式把佔位符替換為傳入的引數:query.bindValue(":username", username);
  4. 所有的佔位符都替換好後,呼叫 query.exec(); 執行 SQL 語句
  5. 遍歷查詢結果

佔位符的格式為: 後跟一個單詞,如 :username

思考一下下面幾個問題:
  1. SELECT * FROM user WHERE username=:username AND password=:password 的佔位符是什麼呢?
  2. SQL 裡的字串需要用 ‘’ 括起來嗎?
  3. 如果傳入的引數是 QDateTime 型別,佔位符應該怎麼寫?
答案:
  1. 這條 SQL 語句裡有 2 個佔位符,分別為 :username 和 :password(不要想成是 username AND password=:password
  2. 不需要。SQL 裡字串需要用 '' 括起來,但是在這裡不需要,Qt 在替換引數的時候會智慧的根據引數的型別判斷是否需要加上 '',如果傳入的字串引數裡有 ',也會智慧的將其轉義,所以避免了SQL 注入攻擊
  3. 寫法也是一樣的,: 後跟一個單詞,可以看看下面的這個例子
/**
 * 輸出 2015-02-01 10:10:10 後建立的 blog.
 */
void outputBlogWithPreparedQuery() {
    QDateTime dateTime = QDateTime::fromString("2015-02-01 10:10:10", "yyyy-MM-dd hh:mm:ss");

    QSqlQuery query;
    query.prepare("SELECT * FROM blog WHERE created_time>:createdTime");
    query.bindValue(":createdTime", dateTime);
    query.exec();

    while (query.next()) {
        qDebug() << QString("Id: %1, Content: %2, Created_Time: %3")
                    .arg(query.value("id").toInt())
                    .arg(query.value("content").toString())
                    .arg(query.value("created_time").toDateTime().toString("yyyy-MM-dd hh:mm:ss"));
    }
}

輸出:

Id: 2, Content: Content of blog 2., Created_Time: 2015-02-02 20:20:20

什麼時候使用 Prepared Query 呢?插入時能使用嗎?刪除時能使用嗎?
  1. 如果傳入引數來構造 SQL 語句,為了避免 SQL 注入攻擊,所以這時需要使用
  2. 使用 Prepared Query 的方式構造的 SQL 語句比用原始的字串相加的方式拼湊 SQL 看上去可讀性好很多
  3. 插入和刪除語句都能用

4. 曾經使用 LIKE 查詢的時候遇到點困難

查詢名字裡有 o 的所有使用者:SELECT * FROM user WHERE username LIKE '%o%',開始時使用

query.prepare("SELECT * FROM user WHERE username LIKE '%:match%'");
query.bindValue(":match", "o");

但是查詢結果為空,弄了好久後來才發現,使用 Prepared Query 構造 SQL 語句,LIKE 之後不能有 '''' 之間的內容由引數傳入,如下:

query.prepare("SELECT * FROM user WHERE username LIKE :match");
query.bindValue(":match", "%o%");

5. 多表查詢時欄位名衝突

列出所有的 user,如果 user 有 blog,則列出 blog:SELECT * FROM user LEFT JOIN blog ON user.id = blog.user_id。在資料庫客戶端執行這條 SQL 語句結果如下圖:

有 2 個列名都叫 id,第一個 id 是 user 表的 id,第二個 id 是 blog 表的 id。執行下面的程式:

void outputUserAndBlog() {
    QSqlQuery query("SELECT * FROM user LEFT JOIN blog ON user.id = blog.user_id");

    while (query.next()) {
        qDebug() << query.value("id").toInt();
    }
}

輸出:

1
2
3

取到的是第一列的 id,即 user 表的 id,並沒有輸出 blog 表的 id。如果我們想取得 blog 表的 id 應該怎麼做呢?顯然上面的 SQL 不行,但是我們可以給查詢欄位重新命名

void outputUserAndBlog() {
    QSqlQuery query("SELECT user.id as user_id, blog.id as blog_id, blog.content as content "
                    "FROM user "
                    "LEFT JOIN blog ON user.id = blog.user_id");

    while (query.next()) {
        qDebug() << QString("User_Id: %1, Blog_ID: %2, Blog_Content: %3")
                    .arg(query.value("user_id").toInt())
                    .arg(query.value("blog_id").toInt())
                    .arg(query.value("content").toString());
    }
}

輸出:

User_Id: 1, Blog_ID: 1, Blog_Content: Content of blog 1.
User_Id: 2, Blog_ID: 2, Blog_Content: Content of blog 2.
User_Id: 3, Blog_ID: 0, Blog_Content:

通過給查詢欄位重新命名的方式,解決了多表查詢時欄位名衝突的問題。

插入操作

/**
 * 向 user 表裡插入一個 user
 * @param username
 * @param password
 */
void insertUser(const QString &username, const QString &password) {
    QSqlQuery query;
    query.prepare("INSERT INTO user (username, password) VALUES (:username, :password)");
    query.bindValue(":username", username);
    query.bindValue(":password", password);
    query.exec();
}

呼叫 insertUser("Qter", "secret") 可以看到資料庫裡多出了剛才插入的資料。

id username password email mobile
1 Alice passw0rd NULL NULL
2 Bob Passw0rd NULL NULL
3 Josh Pa88w0rd NULL NULL
4 Qter secret NULL NULL

刪除操作

/**
 * 刪除名字等於傳入的 username 的 user
 * @param username
 */
void deleteUser(const QString &username) {
    QSqlQuery query;
    query.prepare("DELETE FROM user WHERE username=:username");
    query.bindValue(":username", username);
    query.exec();
}

呼叫 deleteUser("Qter") 則刪除了 user 表裡 username 為 Qter 的所有記錄。

相關推薦

Qt資料庫資料庫常用操作

前面的章節介紹了怎麼使用 Qt 連線訪問資料庫 SQLite 和 MySQL,在這一節裡將介紹訪問資料庫的常用操作細節,主要是關於QSqlDatabase,QSqlQuery 的運用,以及資料庫訪問安全相關的SQL 注入攻擊。 小提示1. 現在比較推薦資料庫設計時每個

資料庫MYSQL基本操作

一、建立 1、修改主鍵 原本沒有主鍵,新增主鍵 如: 表product中沒有主鍵,現需要把pid修改為主鍵 mysql> alter table product add primary key(pid); 注意:原本有主鍵的,需先刪掉原本的主

Qt資料庫資料庫連線池

在前面的章節裡,我們使用了下面的函式建立和取得資料庫連線: void createConnectionByName(const QString &connectionName) { QSqlDatabase db = QSqlDatabase::addDatabase("QMYS

Mongodb對資料庫(DB)的常用操作

1、檢視所有庫 show dbs 2、切換資料庫/新建資料庫 use mydb 3、檢視當前庫 db 需要注意的是:<use 新庫>這個命令並不會馬上建立真正的實體庫,只有往裡面插入資料的時候才會建立庫。 4、刪除資料庫 db.dropDatabase() 雖然是刪除newd

MySQL資料庫安裝和常用操作(轉)

檢查Linux系統中是否已經安裝了MySQL,輸入命令嘗試開啟MySQL服務: sudo service mysql start 如果提示是這樣的,則說明系統中沒有 MySQL,需要繼續安裝: mysql: unrecognized service 在Ubuntu上安裝MySQL,最

redis資料庫介紹和常用操作

一、redis介紹 Redis是一個速度非常快的非關係資料庫,它可以儲存鍵(key)與5種不同型別的值(value)之間的對映(mapping),可以將儲存在記憶體的鍵值對資料持久化到硬碟,可以使用複製特性來擴充套件讀效能,還可以使用客戶端分片來擴充套件寫

Oracle資料庫 匯入匯出常用操作命令

該命令在“開始選單>>執行>>cmd”中執行 一、資料匯出(exp.exe) 1、將資料庫orcl完全匯出,使用者名稱system,密碼accp,匯出到d:\daochu.dmp檔案中  exp system/[email protect

tp5--資料庫查詢的常用操作

  首先,我們要先明確,我們平時經常使用那些操作,我看了開發手冊,主要是連貫操作比較多。 連貫操作有: field, order, limit, page, GROUP, HAVING, cache, 其中,如果我們要使用聚合查詢,GROUP,HAVING,都是有可能用的上的,

MYSQL資料庫----表的操作詳解

此篇主要介紹資料庫中表的操作。資料庫是表的容器,表,必須輸入某個資料庫,因此在建立表之前要指明資料庫。1.表的建立列定義: 列名   列的資料型別   [列的屬性(約束)]建立表的SQL命令:create table 表名(列結構) [表選項];查看錶的定義,可以用DESCR

資料庫的一些常用操作總結

建立表 格式: create table 表名( 欄位名 型別(長度) 約束, 欄位名 型別(長度) 約束 ); 主鍵約束 主鍵是用於標識當前記錄的欄位。它的特點是非空,唯一。在開發中一般情況下主鍵是不具備任何含義,只是用於標識當前記錄。 格式

JDBC(3)JAVA連線資料庫 抽象DAO操作

抽象DAO操作 關於所有的表操作都會對應一些操作,我們都會把這些抽取到對應的DAO中。那麼存在大量的重複操作,是否可以抽出通用的部分,供大家繼承使用。 把DAO的操作先寫成介面,把通用的操作提煉出來。 實現操作 根據主鍵查詢 查詢所有 增加、刪除、修改、記

linux 下面oracle資料庫的一些常用操作,包含啟動arcgissde

1、啟動或者關閉oralce資料庫(12C版本)  以oracle身份登入資料庫,命令:su - oracle (2) 進入Sqlplus控制檯,命令:sqlplus /nolog (3) 以系統管理員登入,命令:connect /as sysdba (4) 啟動

mysql5.7 使用者、資料庫、許可權常用操作

mysql 使用者、資料庫、許可權常用操作 系統資訊 作業系統: macOS High Sierra 10.13.6 mysql版本: MySQL Community Server 5.7.18 登入 使用root 使用者登入mysql

資料庫常用資料字典整理】

資料字典dict總是屬於Oracle使用者sys的。 1、使用者:  select username from dba_users; 改口令:  alter user spgroup identified by spgtest; 2、表空間:  select *

spark中的scalaAPIRDDAPI常用操作

appname 轉換 成了 size pre esc atm rgs new package com.XXX import org.apache.spark.storage.StorageLevel import org.apache.spark.{SparkConf,

三劍客sed常用操作

linux sed 行操作 SedSed是一個強大的文本處理工具可以采用正則匹配,對文本進行插入刪除修改等操作Sed處理的時候,一次處理一行,每一次把當前處理的存放在臨時緩沖區,處理完後輸出緩沖區內容到屏幕,然後把下一行讀入緩沖區,如此重復,直到結尾。1、命令格式和參數sed [-nefr] [動

微電子新手入門Cadence常用操作——波形圖的匯出

模擬結束後,進入模擬波形介面,【File】-【Print...】,彈出對話方塊 一種是輸出.pdf格式的,一種是輸出.ps格式的。點選右邊的【Properties】,進行相應的設定,預設即可,也可以稍微調整修改一下,點選【OK】。 點選【Options>>】

微電子新手入門Cadence常用操作——原理圖/版圖的匯出

原理圖和版圖的匯出步驟是一致的,這裡以匯出黑白原理圖為例介紹。        1)開啟相應的schematic。       2)在Virtusuo Schematic Editor中,【File

微電子新手入門Cadence常用操作——安裝印表機

Cadence Plotter即為Cadence提供的虛擬印表機,可以把設計列印成*.ps (or *.eps)檔案,這種檔案格式為向量圖形,可以後續轉換成*.wmf 或者其他合適的格式在 Microsoft Visio 裡打散編輯。全新安裝的 Cadence 預設是沒有配置虛擬印表機的,需要配置虛

Python 字串常用操作

字串表示:str與repr的區別str()函式把值轉換為合理形式的字串,便於理解repr()函式是建立一個字串,以合法的Python表示式形式來表示值。如下: #-*-encoding:utf-8-*- print repr("hello repr") print str("hello str")