技術人如何利用 github+Jekyll ,搭建一個獨立免費的技術博客

上次有人留言說,技術博客是程序員的標配,但據我所知絕大部分技術同學到現在仍然沒有自己的技術博客。原因有很多,有的是懶的寫,有的是怕寫不好,還有的是一直想憋個大招,幻想做到完美再發出來,結果一直胎死腹中。但其實更多程序員是不知道如何去搭建一個博客,其實如今搭建一個個人技術博客非常簡單,其中最簡單搭建方式莫屬使用 GitHub Pages + Jekyll 了,我的博客就是使用這種技術。

GitHub Pages

Github Pages 是面向用戶、組織和項目開放的公共靜態頁面搭建託管服務,站點可以被免費託管在 Github 上,你可以選擇使用 Github Pages 默認提供的域名 github.io 或者自定義域名來發布站點。Github Pages 支持 自動利用 Jekyll 生成站點,也同樣支持純 HTML 文檔,將你的 Jekyll 站點託管在 Github Pages 上是一個不錯的選擇。

使用 Github Pages 搭建博客有以下幾個優點:

  • 完全免費,其中服務器、流量、域名什麼的都管,完全零費用搭建一個技術博客
  • 寫博客就是提交代碼,讓寫作和編程的體驗保持一致
  • 支持綁定自己的域名
  • 提供流行的網頁主題模板

缺點也是有的:

  • 不支持動態內容,博客必須都是靜態網頁,一般會使用 Jekyll 來構建內容。
  • 博客不能被百度索引,因 Github 和百度有過節,所以 Github 就把百度給屏蔽了。
  • 倉庫空間不大於1G
  • 每個月的流量不超過100G
  • 每小時更新不超過 10 次

Github Pages 使用 Jekyll 來構建內容,那麼 Jekyll 是什麼呢?

Jekyll 介紹

Jekyll 是一個簡單的博客形態的靜態站點生產機器。它有一個模版目錄,其中包含原始文本格式的文檔,通過一個轉換器(如 Markdown)和我們的 Liquid 渲染器轉化成一個完整的可發布的靜態網站,你可以發布在任何你喜愛的服務器上。Jekyll 也可以運行在 GitHub Page 上,也就是說,你可以使用 GitHub 的服務來搭建你的項目頁面、博客或者網站,而且是完全免費的。

但如果我們只是在 GitHub 上面使用的話,到不需要知道 Jekyll 的語法,一般 Github 會自動將我們寫的 Markdown 文件轉換成靜態頁面。使用 Jekyll 需要使用 Markdown 語法來寫你的文章,不過 Markdown 語法非常簡單,做為程序員來講基本上兩三天就掌握了,大家也可以參考這篇文章:。

給大家分享一些 Jekyll 主題,這個網站下有很多 主題,大家可以根據自己的愛好去選擇博客主題。

我的個人博客

我的博客經過了三個階段,第一個階段,完全依託於使用 GitHub Pages 來構建;第二個階段,將博客託管於國外的一個服務商;第三個階段,服務器遷移回到國內、域名備案。之前也寫過幾篇關於技術博客的文章,如下:

使用 Github Pages + Jekyll 構建一個技術博客很簡單,基本上步驟就是網上找一個自己喜歡的主題,直接 Fork 到自己的 Github ,然後在刪掉原博客中的內容,在上傳自己的文章即可,以我自己的博客為例。

我的博客最初使用的是,但這個主題已經盡兩年多都沒有更新了。因此後期我在這個主題的基礎上做了一些改動,其中有依賴組件的更新,結合個人情況對個別頁面進行了改版,就成為了現在的樣子:

使用這個主題的原因是,我比較喜歡簡潔大氣的風格,並且此博客主題對代碼展示支持良好。

快速構建一個博客

以我的博客為例,介紹如何最快搭建一個博客。這也是我博客經歷的第一個階段。

1、首先打開地址,點擊 Fork 按鈕將代碼複製一份到自己的倉庫。

過上一分鐘,你的 github 倉庫發現一個 ityouknow.github.io 項目。

2、刪除 CNAME 文件

刪除項目中的 CNAME 文件,CNAME 是定製域名的時候使用的內容,如果不使用定製域名會存在衝突。

3、設置 GitHub Pages

點擊 Settings 按鈕打開設置頁面,頁面往下拉到 GitHub Pages 相關設置,在 Source 下面的複選框中選擇 master branch ,然後點擊旁邊的 Save 按鈕保存設置。

4、重命名項目

點擊 Settings 按鈕打開設置頁面,重命名項目名稱為:github_username.github.io。

github_username 是你的 github 登錄用戶名

5、重命名之後,再次回到 Settings > GitHub Pages 頁面

會發現存在這樣一個地址:

這個時候,你訪問此地址已經可以看到博客的首頁,但是點擊文章的時鏈接跳轉地址不對,這是因為少配置了一個文件。

6、配置 _config.yml

打開項目目錄下的 _config.yml 文件,修改以下配置:

repository: github_username/github_username.github.io
github_url: https://github.com/github_username
url: https://github_username.github.io

這時候在訪問地址: https://github_username.github.io,就會發現博客就已經構建完成了。剩下的事情就是去項目的 _posts 目錄下刪除掉我的文章,然後按照 Jekyll 的語法就寫自己的文章就好了。

github_username 為你的 github id。

自定義域名

雖然通過地址https://github_username.github.io可以正常訪問博客,但是技術小夥伴們肯定有人想使用自己的域名訪問博客,這樣的需求 GitHub Pages 也是支持的。

首先需要設置域名解析,將域名的地址指向自己的 github 博客地址。這裏以萬網的域名配置為例,選擇需要設置的域名點擊解析,在域名解析頁面添加以下兩條記錄

紅框內,需要填寫自己github_username值。

然後重新打開項目的 Settings > GitHub Pages 頁面,Custom domain 下的輸入框輸入剛才設置的域名:xxx.com,點擊保存即可。

重新配置 _config.yml

打開項目目錄下的 _config.yml 文件,修改以下配置:

url: http://www.xxx.com

等待一分鐘之後,瀏覽器訪問地址:www.xxx.com 即可訪問博客。

自定義 DIY 博客

一般同學到上面這一步也就完成了,基本滿足了 80% 技術同學的需求。但還是有一些同學們有更高的追求,比如說使用 Github Pages 雖然簡單方便,但是不能被百度檢索白白流失了大量的流量,還有一個原因有些時候,博客網絡訪問穩定性不是很高。

當時我在國外有幾個虛擬機,本來用作它用,後來在上面安裝了一個 Nginx 作為靜態頁面的服務器。首先我在本機(win10)安裝了 Jekyll 環境,將 Github 上的博客代碼下載下來之後,在本機編譯成靜態的 Html ,然後手動上傳到服務的 Nginx 目錄下;然後將域名指向虛擬機。

非常不建議大家實踐以上這段內容,win10 上面安裝 Jekyll 環境是一段慘痛的經歷。

就這樣很麻煩的步驟我用了幾個月後,實在是受不了了,一方面因為服務器在國外,有時候仍然不穩定(可能因為服務器安裝了代理),另一方面我需要使用一些功能,使用這些功能的前提是網站需要備案,那段時間騰訊雲在做活動,就把博客又從國外搬了回來,順便重新優化了一下流程。

仍然把博客託管在 Github 上面,每次提交完代碼后,在騰訊雲上面執行一個腳本,這個腳本會自動從 Github 拉取最新更新的文件,並自動生產靜態的 Html 文件推送到 Nginx 目錄,域名重新指向這台服務器。可以在 Github 上面設置一些鈎子,當提交代碼的時候自動觸髮腳本,也可以定時觸髮腳本來發布文章。

腳本內容如下:

cd /usr/local/ityouknow.github.io
git pull http://github.com/ityouknow/ityouknow.github.io.git
jekyll build --destination=/usr/share/nginx/html

執行此腳本的前提是安裝好 git\jekyll 環境,這個網上有很多案例,這裏就不再多描述了。
關於 Jekyll 環境搭建和使用可以參考這裏:

自動化部署

這两天看到,我也按照他的步驟實踐了一番,很好用,所以把自動化部署這段寫補上。

配置 Webhook

在開發過程中的 Webhook,是一種通過通常的 callback,去增加或者改變 Web page或者 Web app 行為的方法。這些 Callback 可以由第三方用戶和開發者維持當前,修改,管理,而這些使用者與網站或者應用的原始開發沒有關聯。Webhook 這個詞是由 Jeff Lindsay 在 2007 年在計算機科學 hook 項目第一次提出的。

用大白話講就是,代碼倉庫在收到代碼提交的時候,會自動觸發一個 url 類型的通知,你可以根據這個通知去做一些事情,比如提交了代碼就自動去部署項目。

我們的自動部署博客也是利用了這個機制,Github 自帶了 Webhook 功能,我們直接配置即可使用。

在 Github 倉庫的項目界面,比如本博客項目 https://github.com/ityouknow/ityouknow.github.io,點擊 Setting->Webhooks->Add Webhook,在添加 Webhooks 的配置信息,我的配置信息如下:

Payload URL: http://www.ityouknow.com/deploy
Content type: application/json
Secret: 123456

如下圖:

服務器接受推送

我們需要在博客的服務器上面建立一個服務,來接收 Github 提交代碼后的推送,從而來觸發部署的腳本。 Github 上有一個開源項目可以做這個事情 。

這個開源項目目的很單純,就是負責接收 Github 推送過來的通知,然後執行部署腳本,不過他是使用 NodeJs 來開發的,所以我們先需要在 Centos 上面按照 Node 環境。

centos7 安裝 Node 環境

首先添加源

sudo rpm -ivh https://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-7-11.noarch.rpm

//yum安裝node.js
yum install -y nodejs

然後在安裝 github-webhook-handler

npm install -g github-webhook-handler     #安裝 github-webhook-handler
#如果沒有安裝成功,可以選擇法2來安裝
npm install -g cnpm --registry=http://r.cnpmjs.org
cnpm install -g github-webhook-handler

安裝成功之後,我們需要添加一個腳本。進入到安裝目錄下:

cd  /usr/lib/node_modules/github-webhook-handler

新建 deploy.js

vi deploy.js

腳本內容如下:

var http = require('http')
var createHandler = require('github-webhook-handler')
var handler = createHandler({ path: '/deploy', secret: 'ityouknow' }) //監聽請求路徑,和Github 配置的密碼
 
function run_cmd(cmd, args, callback) {
  var spawn = require('child_process').spawn;
  var child = spawn(cmd, args);
  var resp = "";
 
  child.stdout.on('data', function(buffer) { resp += buffer.toString(); });
  child.stdout.on('end', function() { callback (resp) });
}
 
http.createServer(function (req, res) {
  handler(req, res, function (err) {
    res.statusCode = 404
    res.end('no such location')
  })
}).listen(3006)//監聽的端口
 
handler.on('error', function (err) {
  console.error('Error:', err.message)
})
 
handler.on('push', function (event) {
  console.log('Received a push event for %s to %s',
    event.payload.repository.name,
    event.payload.ref);
  run_cmd('sh', ['/usr/local/depoly.sh'], function(text){ console.log(text) });//成功后,執行的腳本。
})

腳本的作業就是啟動一個監聽端口來接收請求,接收到請求后執行部署腳本,腳本內容的關鍵點已經標註上註釋。

部署博客的腳本如下:depoly.sh

echo `date`
cd /usr/local/ityouknow.github.io
echo start pull from github 
git pull http://github.com/ityouknow/ityouknow.github.io.git
echo start build..
jekyll build --destination=/usr/share/nginx/html

就是拉取代碼,進行部署而已。

這個腳本的啟動需要藉助 Node 中的一個管理 forever 。forever 可以看做是一個 nodejs 的守護進程,能夠啟動,停止,重啟我們的 app 應用。

不過我們的先安裝 forever,然後需要使用 forever 來啟動 deploy.js 的服務,執行命令如下:

npm install forever -g   #安裝
$ forever start deploy.js          #啟動
$ forever stop deploy.js           #關閉
$ forever start -l forever.log -o out.log -e err.log deploy.js   #輸出日誌和錯誤
/root/node-v8.12.0-linux-x64/lib/node_modules/forever/bin/forever start -l forever.log -o out.log -e err.log deploy.js

如果報錯:
/root/node-v8.12.0-linux-x64/lib/node_modules/forever/bin/forever start -a -l forever.log -o out.log -e err.log deploy.js

同時一般情況下,我們不會對外保留很多端口,所以需要通過博客的地址來轉發,需要在 Nginx 上面添加一個轉發配置,用來監聽的 /deploy 請求轉發到 nodejs 服務上,配置代碼如下:

location = /deploy {
     proxy_pass http://127.0.0.1:3006/deploy;
}

這樣我們整個自動化部署就完了,每次提交代碼時,Github 會發送 Webhook 給地址http://www.ityouknow.com/deploy,Nginx 將 /deploy 地址轉發給 Nodejs 端口為 3306 的服務,最後通過 github-webhook-handler 來執行部署腳本,已到達自動部署的目的。

以後只需要我們提交代碼到 Github ,就會自動觸發博客的自動化部署。

可能會出現的問題

有一些小夥伴反饋在克隆博客的時候出現了一些問題,在這裏集中回復一下。

1、克隆博客后格式丟失

這是很多讀者反饋的第一個問題,因為我的博客 css 和 圖片是放到另外一個域名下的:www.itmind.net ,因此這塊大家克隆過去需要改成本地的。

主要涉及的文件 ityouknow.github.io\_includes 目錄下 head.html 和 footer.html 兩個文件夾,將文件中的 http://www.ityouknow.com/xxx/xxx 改為相對路徑/xxx/xxx即可。

2、留言功能丟失

這裏就需要大家修改一下 _config.yml 中 gitalk 的配置信息。具體如何操作大家可以參考這篇文章 。註冊完之後,需要在 _config.yml 配置以下信息:

gitalk:
    owner: ityouknow
    repo: blog-comments
    clientID: 61bfc53d957e74e78f8f
    clientSecret: 31c61e66cdcc9ada8db2267ee779d0bdafac434c

將這裏改成你註冊好的信息

3、博客

博客現在還缺檢索功能,下一頁和上一頁功能、系列文章優化查看的功能,大家克隆後有完善功能的,也請幫忙留意,共同把這個博客完善的更好。

最後,大家可以在這篇文章下留下你的個人博客地址,方便同行們觀賞、交流、學習。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

Mirantis 收購 Docker EE | 雲原生生態周報 Vol. 28

作者 | 禪鳴、進超、心水、心貴

業界要聞

Mirantis 是一家紮根於 OpenStack 的雲公司,最近專註於 Kubernetes。該公司剛剛收購了 Docker 的企業部門,該業務部門包括 Docker Enterprise 技術平台及所有相關的知識產權、約 400 名員工中的 300 人、750 家企業客戶以及所有企業夥伴關係。

Project Quay 包含一系列在 Apache 2.0 和其他開源許可證下許可的開源軟件。它遵循一個帶有維護者委員會的開源治理模型。

KubeCon + CloudNativeCon North America 2019 於 11 月 18 日 在 San Diego 正式召開。

上游重要進展

KEP

主要為了解決以下問題:

  • PreSidecars 將在普通容器之前啟動,但在 init 容器之後啟動,這樣它們就可以在您的主進程開始之前準備好;
  • PostSidecars 將在普通容器之後啟動,以便它們在您的主進程啟動后可以執行某些操作,例如更新 css 文件,轉發日誌等。

主要為了解決以下問題:

  • Client/Server 版本偏移;
  • API 擴展支持;
  • 提供更簡單的選項來與 cli 工具進行集成(例如 jq);
  • 提供與 unix cli 標準集成的接口(xargs/find -exec/globbing);
  • 保留配置註釋,結構等。

IP地址類型分解為IPv4IPv6。並逐步棄用原有地址類型,其在 1.17 中對新的 EndpointSlices 無效,然後在 1.18 中變得完全無效。

K8S PR

提供一種在 --show-enable-metrcis-for-version 設置時重新註冊隱藏指標的機制。

有兩個原因:

  • 新版本中 http.CloseNotifier 已經被廢棄;
  • 如果請求協議為 HTTP/2.x,原始代碼使用 http.CloseNotifier 的情況下,每一個 Watch 將多花費 1 個 goruntine。在大規模場景下,過多的 goruntine 對 API Server 是一個非常大的負擔和性能瓶頸。

在 Windows 上使用 Containerd 時,將由 kubelet 管理“ C: Windows  System32  drivers  etc  hosts”文件。

為了減少 service controller 在節點有更新時,更新 backend 的延遲。

當提供客戶端證書證書文件后,始終保持從磁盤重新啟動證書文件以進行新連接,並在證書更改時關閉連接。

Knative

當前 Kubernetes 社區(Kubebuilder 和 Metacontroller)正在研究控制平面可伸縮性,認為雖然用於 Kubernetes 工作的”無服務器控制器”是一個思想實驗,但距離我們並不遠,並且在技術上也是可行的。

開源項目推薦

阿里雲容器服務團隊自研 CNI 網絡插件,支持 VPC 和 ENI 等。

Vmware 開源基於 OVS 的 Kubernetes 網絡方案。

KubeSphere 是在 Kubernetes 之上構建的以應用為中心的多租戶容器管理平台,目前已經達到 GA 狀態。

具有硬件資源感知工作負載放置策略的 Kubernetes Container Runtime Interface 代理服務。

本周閱讀推薦

CRDs/controllers 是 Kubernetes 中重要的組件,它們會將集群內的各種資源調整到期望狀態。學習 Reconciling 可以幫助我們更好的理解 CRDs/controllers 是如何工作的。

通過漫畫的形式對 Openshift 及相關產品加以介紹,比較有趣。

隨着時間的推移,Docker 開始根植於我們的日常生活當中。然而,Docker 一切輝煌的背後,技術社區中開始有不少人認為 Docker 正一路朝着沉沒的方向前進。那麼,這樣的判斷有沒有依據?Docker 真的快要不行了嗎?或者說,這隻是技術領域當中部分小年輕們一廂情願的偏執?

由於目前國內並沒有比較好的 Go 語言書籍,而國外的優秀書籍因為英文的緣故在一定程度上也為不少 Go 語言愛好者帶來了一些學習上的困擾。

為了加快擴散 Go 愛好者的國內群體,譯者在完成 《The Way to Go》 一書的閱讀後,決定每天抽出一點時間來進行翻譯工作,並以開源的形式免費分享給有需要的 Go 語言愛好者。

在 Istio 服務網格中,每個 Envoy 佔用的內存也許並不算多,但所有 sidecar 增加的內存累積起來則是一個不小的数字。在進行商用部署時,我們需要考慮如何優化並減少服務網格帶來的額外內存消耗。

Buoyant 創始人、Service Mesh 技術的提出者、第一個 Service Mesh Linkerd 的作者 Willian Morgan 為您解析 Service Mesh 現狀。

“ 阿里巴巴雲原生微信公眾號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術公眾號。”

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

面向對象和面向過程到底是怎麼回事?

今天下午在一個組的項目回顧會議上,這個同事講了自己用DDD思想對三個模塊的重構。把之前在Service層的一些業務邏輯下沉到了領域層里,由之而引起的討論。

部門經理:“其實你的業務邏輯總體並沒有少,只是把邊界重新劃分了一下。”

一起參与開發的同事:“在第二個模塊中(任務系統,包括了任務拆分,狀態跟蹤等)這種思想比較有優勢,在一三項目中不是很明顯。”

於是引出了我的一個問題:“到底什麼是面向對象,什麼是面向過程,在什麼情況下適合面向對象,什麼場景下適用於面向過程?”

  • 以C語言和Java語言為例: C語言沒有類,但是有結構體,結構體中不能有函數,只能有屬性。這說明了什麼?說明了在面向過程的思考方式中,數據和操作是嚴格分離的
  • C語言中為什麼函數需要定義到調用此函數的前面,也就是說先聲明后調用?如果按照流程化的思路來看這種設計方式,想要調用一個子流程,勢必要在調用之前就定義好
  • 而在java的類中,就沒有函數定義先後的問題,這與面向過程和面向對象的最小定義粒度有關,面向過程的最小定義粒度為流程(方法、操作、函數),而在面向對象中,最小定義粒度為對象,這個對象的行為沒有先後,包含在對象這個大的容器中。
  • 封裝、抽象、繼承、多態其實就是類比的對象進行的建模,比如以人為例,人有些屬性不想示人,有些屬性只能給指定的人了解,這就是封裝。人掌握的知識其實是現象的一種抽象。人繼承來來自父母的一些生活習慣,而又有所不同,這就是多態。
  • 歸總, 子類相對父類來說有不同的模型(對真實世界的建模),這是4種面向對象的終極原因。 
  • 為什麼面向對象的思考方式更有利於擴展維護?拿一個工作崗位為例,一個人在一個工作崗位上,如果有一天這個崗位有了更多的工作要求,如果改動量較小,那麼對該崗位的人進行技能培訓就可以了。如果要求多到一種程度,拆分成兩個人,或者拆分成多個崗位。而如果用面向過程的思路,那麼每次改動,都相當於多了一個流程?(這裏存疑,多流程的問題在哪?難維護的理由是什麼?這裏我沒有想明白
  • 面向過程要求人有更好的流程化思維方式,面向對象要求人有更好的抽象思維方式。那麼如果有一天出現一個“面向文檔編程”呢?要求人有更好的把問題描述清楚的表達能力。換句話說, 面向過程就是面向流程思考,面向對象就是針對模型思考

最後距離,如果我們描述入職流程,一個大牛的入職流程可能和一個應屆生的入職流程完全不一樣,如果把入職這個行為寫到employee的方法中,那麼這就是面向對象的寫法,如果維護一個入職流程的方法,根據不同的人用switch case的方式進行不同行為的跳轉,那麼就是面向過程。

面向過程就是面向流程思考,面向對象就是針對模型思考

 

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

最強新能源汽車 奧迪發出核動力超跑

為什麼奧迪MesarthimF-Tron Quattro是最強新能源汽車?因為它的複雜程度,已經超出了你的物理知識認知。如果對新能源汽車大概分個等級,那麼“二次電池”驅動的純電動車是一級,插電式混合動力是二級,太陽能汽車三級,燃料電池汽車四級,那麼最強的是?當然是核動力汽車。  
  據稱,奧迪未來的超級跑車即是一款核動力汽車,代號Mesarthim F-Tron Quattro,由俄羅斯工程師操刀設計。外型前衛十足,頗有蝙蝠車的味道。   核動力主要部件核反應爐與離子發射器位於前後軸之間,旁邊是發熱裝置,產生的蒸汽進而驅動電機發電,動力電池安裝在前艙,使用四個輪轂電機驅動車輪前進,同時還有電機驅動離子發射器、冷凝器等,除了核燃料供給,其它整個系統構成一個閉環生態。  
  由於動力系統是個獨立部分,導致其它部件的安裝位置是個問題,為解決這個問題,工程師設計了一套叫做“Solid Cage”的獨立底盤,這個底盤是聚合物材料,可以3D列印出來,而且可以獨立拆卸。   除此以外,底盤上還有一個平底罐,裡面裝有磁流體,在有磁性的路面上行駛時,車子就會產生下壓力,過彎的時候能抵制側傾力,直行的時候抑制抬頭點頭。   雖然奧迪暫時沒有給出這款車具體推出時間表,總體來說還是值得稱讚的。   文章來源:蓋世汽車

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

CSS(8)—通俗講解定位(position)

CSS(8)—通俗講解定位(position)

CSS有三種基本的定位機制: 普通流浮動定位。前面兩個之前已經講過,詳見博客:

1、

2、

3、

一、為什麼要用定位?

如果說浮動關鍵在一個 “浮” 字上面, 那麼 我們的定位,關鍵在於一個 “位” 上。

我們來思考下定位用於的場景。

1、打Log標籤

比如你想在商品的圖片想打個標籤比如:包郵、最新上架等等。

怎麼做比較好呢,如果你要粗暴那就直接ps在圖片上添加標籤。只是這樣有個很大的弊端,比如你要添加新標籤你需要重現修圖,比如商品之前包郵後面不包郵了,

那你又需要重新p圖。這樣肯定是不合適的。那怎麼做比較合適?

其實很簡單,將商品圖片和標籤的標籤分開來。然後通過css在商品圖片上添加標籤。這個時候通常會定位去完成。

2、切換Banner

有些商城的首頁都會有個Banner,這裏 左右的箭頭下面的小點點一般也是用定位來做。

3、廣告位窗口

有些位置在左右側會有固定的廣告窗口,不論怎麼滑動頁面這個廣告窗口都是在固定位置

這個就需要用到固定定位了。

二、定位概念

1、定位的分類

在CSS中,position 屬性用於定義元素的定位模式,其基本語法格式如下:

選擇器 {position:屬性值;}

屬性值

這裏還有個概念就是 邊偏移 因為你定位肯定要指定定位在哪裡,所以需要通過 邊偏移 來指定。

所以定位是要和邊偏移搭配使用的。不過對於static(靜態定位)設置邊偏移是無用的。

2、靜態定位(static)

static 是此屬性的默認值。這時候,我們稱那個元素沒有被定位。簡單來說就是網頁中所有元素都默認的是靜態定位。 其實就是標準流的特性。

所以如果需要使用定位那這裏就不能是這個默認值了。

注意 在靜態定位狀態下,此時 top, right, bottom, left 和 z-index 屬性無效。

3、相對定位(relative)

它的主要特點如下

1、 參照元素原來的位置進行移動。
2、 通過"left"、 "top"、 "right"、 "bottom" 屬性進行定位。
3、 元素原有的空間位保留。
4、 元素在移動時會蓋住其他元素。

舉例說明

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>相對定位</title>
        <style type="text/css">
            #one {
                width: 120px;
                height: 120px;
                background: #E19D59;
            }
            #two {
                width: 120px;
                height: 120px;
                background: #FF0000;
                position: relative;   /*設置相對定位*/
                left: 20px;           /*設置距離左邊偏移位置*/
                top: 20px;            /*設置距離頂部偏移位置*/
            }
            #three {
                width: 120px;
                height: 120px;
                background: #008000;
            }
        </style>
    </head>
    <body>      
        <div id="one">div1</div>
        <div id="two">div2</div>
        <div id="three">div3</div>        
    </body>
</html>

運行結果

通過我們這個示例我們可以看出

1、它的左右,上下邊偏移的量是根據這個div2原始位置基礎上進行移動的。
2、這個div2它還是個標準流,並沒有浮起來,所以這個位置它還是佔有的。(如果div2浮動那麼div3就會向上移動,這裏顯然沒有)
3、當它偏移后 如果和其它元素有重疊,它會覆蓋其它元素。(div2覆蓋了部分div3元素)

作用 我的理解相對定位主要用途是用來給絕對定位的一個盒子。(下面會解釋這句話)

4、絕對定位absolute

特點

1、參照距離他最近的有定位屬性的父級元素進行移動
2、通過"left"、 "top"、 "right"、 "bottom" 屬性進行定位
3、元素完全脫離文檔流,原有位置不再保留
4、元素在移動時會蓋住其他元素
5、一般我們設置絕對定位時,都會找一個合適的父級將其設置為相對定位。最好為這個具有相對定位屬性的父級設置寬高

舉例說明

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title></title>
        <style type="text/css">
           #father{
                width: 400px;
                height: 400px;
                margin: 100px;
               /*  position: relative;*/
                background: yellow;
            }
            #bd1{
                width: 120px;
                height: 120px;
                background: #E19D59;
            }
            #bd2{
                width: 120px;
                height: 120px;
                background: #FF0000;
                position: absolute;
                left: 20px;
                top: 20px;
            }
            #bd3{
                width: 120px;
                height: 120px;
                background: #008000;
            }
        </style>
    </head>
    <body>  
    <div id="father"> 
        <div id="bd1">div1</div>
        <div id="bd2">div2</div>
        <div id="bd3">div3</div>  
    </div>         
    </body>
</html>

運行結果

從這幅圖可以看出一點

這裏因為父div沒有設置定位,所以它的位置是相對於body進行邊偏移。

這個時候我們將父標籤設置 position: relative;

再刷新頁面

從這張圖很直觀看到:

1、因為父div設置了定位,所以這裏的邊偏移變成都是相對於父div進行偏移(正常貼標籤就是這樣)
2、我們可以看出當設置絕對定位后,該元素已經脫離文檔流,已經浮上來了(因為div2上浮所有div3才會上移)
3、元素在移動時會蓋住其他元素 (div2覆蓋了部分div3)

5、固定定位(fixed)

特點

1、以body為定位時的對象,總是根據瀏覽器的窗口來進行元素的定位
2、通過"left"、 "top"、 "right"、 "bottom" 屬性進行定位
3、元素完全脫離文檔流,原有位置不再保留
4、元素不會隨着文檔流的滑動而滑動

固定定位最大的特點就是第一點,可以理解成它是以可視區域為準,會一直显示在可視區域,屏幕滑動也會显示在定位的位置。

6、四種定位總結

還有比較重要的三點

定位模式轉換

跟 浮動一樣, 元素添加了 絕對定位和固定定位之後, 元素模式也會發生轉換, 都自動轉換為 行內塊元素。

絕對定位的盒子水平/垂直居中

注意 普通的盒子是左右margin 改為 auto就可, 但是對於絕對定位就無效了。

定位的盒子也可以水平或者垂直居中,有一個算法(下面會舉例說明)。

1. 首先left 50%   父盒子的一半大小
2. 然後走自己外邊距負的一半值就可以了 margin-left。

子絕父相

這句話的意思是 子級是絕對定位的話,父級要用相對定位

為什麼會有這個概念,那是因為絕對定位的邊偏移特點是

 如果父元素沒有設置定位,那麼它的位置是相對於body進行邊偏移。如果父元素設置定位,那就根據父元素偏移。

一般我們肯定是希望根據父元素偏移。就好比圖片打標籤,不可能跟着body偏移而是父元素進行定位。而且父元素相對定位最大的好處就是它會佔有位置,因此父親最好是 相對定位。

三、經典示例

1、打上log標記

示例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>log標籤</title>
    <style>
    div {
        width: 310px;
        height: 190px;
        border: 1px solid #ccc;
        margin: 100px auto; 
        position: relative;  /*父選擇相對定位*/
    }
    .top {
        position: absolute; /*子取相對定位*/
        top: 0;             /*位置 左上*/
        left: 0;
    }
    
    </style>
</head>
<body>
    <div>
        <img src="images/log.jpg" alt="" class="top">     <!-- log的圖片 -->
        <img src="images/goods.jpg" height="190" width="310" alt=""> <!-- 商品圖片,長和寬和父div大小一致 -->
    </div>
</body>
</html>

運行結果就是上面的最終結果。

2、定位水平居中

加了定位 浮動的的盒子 margin 0 auto 失效了

代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>水平居中</title>
    <style>
    div {
        width: 200px;
        height: 200px;
        background-color: pink;
        position: absolute;
        /*加了定位 浮動的的盒子  margin 0 auto 失效了*/
        left: 50%;
        margin-left: -100px;  /*減去總寬度一般*/
        top: 50%;
        margin-top: -100px;   /*減去總高度一般*/
    }
    </style>
</head>
<body>
    <div></div>
</body>
</html>

這個這個div就處於整個頁面的居中了,這裏我們來說明下下面這兩個的意思

        left: 50%;
        margin-left: -100px;  /*減去總寬度一般*/

3、輪播圖

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>輪播圖</title>
    <style>
    * {
        margin: 0;
        padding: 0;
    }
    li {
        list-style: none;
    }
    .tb {
        width: 520px;
        height: 280px;
        background-color: pink;
        margin: 100px auto;
        position: relative;
    }
    .tb a {
        width: 24px;
        height: 36px;
        
        display: block;
        position: absolute;
        top: 50%;
        margin-top: -18px;
    }
    .left {
        left: 0;
        background: url(images/left.png) no-repeat;
    }
    .right {
        right: 0;
        background: url(images/right.png) no-repeat;
    }
    .tb ul {
        width: 70px;
        height: 13px;
        background: rgba(255, 255, 255, .3);
        position: absolute; /* 加定位*/
        bottom: 18px;
        left: 50%; /*水平走父容器的一半*/
        margin-left: -35px; /*左走自己的一半*/
        border-radius: 8px;
    }
    .tb ul li {
        width: 8px;
        height: 8px;
        background-color: #fff;
        float: left;
        margin: 3px;
        border-radius: 50%;
    }
    .tb .current {
        background-color: #f40;
    }
    </style>
</head>
<body>
    <div class="tb">
        <img src="images/tb.jpg" >
        <a href="#" class="left"></a>
        <a href="#" class="right"></a>
        <ul>
            <li class="current"></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
        </ul>

    </div>
</body>
</html>

運行結果

參考

1、

2、

你如果願意有所作為,就必須有始有終。(10)

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

五分鐘學會HTML5的WebSocket協議

1、背景

  很多網站為了實現推送技術,所用的技術都是Ajax輪詢。輪詢是在特定的的時間間隔由瀏覽器對服務器發出HTTP請求,然後由服務器返回最新的數據給客戶端的瀏覽器。這種傳統的模式帶來很明顯的缺點,即瀏覽器需要不斷的向服務器發出請求,然而HTTP請求可能包含較長的頭部,其中真正有效的數據可能只是很小的一部分,顯然這樣會浪費很多的帶寬等資源。HTML5新增的一些新協議WebSocket,可以提供在單個TCP連接上提供全雙工,雙向通信,能夠節省服務器資源和帶寬,並且能夠實時進行通信。

2、WebSocket介紹

  傳統的http也是一種協議,WebSocket是一種協議,使用http服務器無法實現WebSocket,

2.1.瀏覽器支持情況

基本主流瀏覽器都支持

2.2.優點

相對於http有如下好處:

  • 1.客戶端與服務器只建立一個TCP連接,可以使用更少的連接。
  • 2.WebSocket服務器端可以主動推送數據到客戶端,更靈活高效。
  • 3.更輕量級的協議頭,減少數據傳送量。

對比輪訓機制

3、WebSocket用法

  我們了解WebSocket是什麼,有哪些優點后,怎麼使用呢?

3.1.WebSocket創建

WebSocket使用了自定義協議,url模式與http略有不同,未加密的連接是ws://,加密的連接是wss://,WebSocket實例使用new WebSocket()方法來創建,

var ws = new WebSocket(url, [protocol] );

第一個參數 url, 指定連接的 URL。第二個參數 protocol 是可選的,指定了可接受的子協議。

3.2.WebSocket屬性

當創建ws對象后,readyState為ws實例狀態,共4種狀態

  • 0 表示連接尚未建立。

  • 1 表示連接已建立,可以進行通信。

  • 2 表示連接正在進行關閉。

  • 3 表示連接已經關閉或者連接不能打開。

Tips:在發送報文之前要判斷狀態,斷開也應該有重連機制。

3.3.WebSocket事件

在創建ws實例對象后,會擁有以下幾個事件,根據不同狀態可在事件回調寫方法。

  • ws.onopen 連接建立時觸發

  • ws.onmessage 客戶端接收服務端數據時觸發

  • ws.onerror 通信發生錯誤時觸發

  • ws.onclose 連接關閉時觸發

ws.onmessage = (res) => {
  console.log(res.data);
};

ws.onopen = () => {
  console.log('OPEN...');
};

ws.onclose=()=>{
 console.log('CLOSE...');
}

3.4.WebSocket方法

  • ws.send() 使用連接發送數據(只能發送純文本數據)

  • ws.close() 關閉連接

4、Demo演示

  了解WebSocket的一些API之後,趁熱打鐵,做一個小案例跑一下。

4.1.Node服務器端

WebSocket協議與Node一起用非常好,原因有以下兩點:

1.WebSocket客戶端基於事件編程與Node中自定義事件差不多。

2.WebSocket實現客戶端與服務器端長連接,Node基本事件驅動的方式十分適合高併發連接

創建一個webSocket.js如下:

const WebSocketServer = require('ws').Server;
const wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function (ws) {
    console.log('client connected');
    ws.on('message', function (message) {
        ws.send('我收到了' + message);
    });
});

打開windows命令窗口運行

4.2.HTML客戶端

新建一個index.html頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webSocket小Demo</title>
</head>
<body>
    <div class="container">
        <div>
            <input type="text" id="msg">
            <button onclick="sendMsg()">發送報文</button>
        </div>
    </div>
    <script>
        const ws = new WebSocket('ws://localhost:8080');
        ws.onmessage = (res) => {
            console.log(res);
        };
        ws.onopen = () => {
            console.log('OPEN...');
        };
        ws.onclose = () => {
            console.log('CLOSE...');
        }
        function sendMsg() {
            let msg = document.getElementById('msg').value;
            ws.send(msg);
        }
    </script>
</body>

打開瀏覽器依次輸入字符1,2,3,每次輸入完點擊發送報體,可見在ws.onmessage事件中res.data中返回來我們發的報文

5、問題與總結

  以上只是簡單的介紹了下WebSocket的API與簡單用法,在處理高併發,長連接這些需求上,例如聊天室,可能WebSocket的http請求更加合適高效。

   但在使用WebSocket過程中發現容易斷開連接等問題,所以在每次發送報文前要判斷是否斷開,當多次發送報文時,由於服務器端返回數據量不同,返回客戶端前後順序也不同,所以需要在客戶端收到上一個報文返回數據后再發送下一個報文,為了避免回調嵌套過多,通過Promise ,async ,await等同步方式解決。關於WebSocket就寫這麼多,如有不足,歡迎多多指正!

參考資料:
《JavaScript高級教程》
《深入檢出NodeJs》

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

【Stream—5】MemoryStream相關知識分享

一、簡單介紹一下MemoryStream

MemoryStream是內存流,為系統內存提供讀寫操作,由於MemoryStream是通過無符號字節數組組成的,可以說MemoryStream的性能可以算比較出色,所以它擔當起了一些其他流進行數據交互安時的中間工作,同時可降低應用程序中對臨時緩衝區和臨時文件的需求,其實MemoryStream的重要性不亞於FileStream,在很多場合,我們必須使用它來提高性能

二、MemoryStream和FileStream的區別

前文中也提到了,FileStream主要對文件的一系列操作,屬於比較高層的操作,但是MemoryStream卻很不一樣,他更趨向於底層內存的操作,這樣能夠達到更快速度和性能,也是他們的根本區別,很多時候,操作文件都需要MemoryStream來實際進行讀寫,最後放入相應的FileStream中,不僅如此,在諸如XmlWriter的操作中也需要使用MemoryStream提高讀寫速度

三、分析MemoryStream最常見的OutOfMemory異常

先看一下下面一段簡單的代碼

 1             //測試byte數組 假設該數組容量是256M
 2             var testBytes = new byte[256 * 1024 * 1024];
 3             var ms = new MemoryStream();
 4             using (ms)
 5             {
 6                 for (int i = 0; i < 1000; i++)
 7                 {
 8                     try
 9                     {
10                         ms.Write(testBytes, 0, testBytes.Length);
11                     }
12                     catch
13                     {
14                         Console.WriteLine("該內存流已經使用了{0}M容量的內存,該內存流最大容量為{1}M,溢出時容量為{2}M",
15                             GC.GetTotalMemory(false) / (1024 * 1024),//MemoryStream已經消耗內存量
16                             ms.Capacity / (1024 * 1024), //MemoryStream最大的可用容量
17                             ms.Length / (1024 * 1024));//MemoryStream當前流的長度(容量)
18                         break;
19                     }
20                 }
21             }
22             Console.ReadLine();

輸出結果:

 

 

 從輸出結果來看,MemoryStream默認可用最大容量是1024M,發生異常時正好是其最大容量。

問題來了,假設我們需要操作比較大的文件,該怎麼辦呢?其實有2種方法可以搞定,一種是分段處理,我們將Byte數組分成等份進行處理,還有一種方式便是增加MomoryStream的最大可用容量(字節),我們可以在聲明MomoryStream的構造函數時利用它的重載版本:MemoryStream(int capacity)

到底使用哪種方法比較好呢?其實筆者認為具體項目具體分析,前者分段處理的確能夠解決大數據量操作的問題,但是犧牲了性能和時間(多線程暫時不考慮),後者可以得到性能上的優勢,但是其允許最大容量是 int.Max,所以無法給出一個明確的答案,大家在做項目時,按照需求自己定製即可,最關鍵的還是要取到性能和開銷的最佳點位,還有一種更噁心的溢出方式,往往會讓大家抓狂,就是不定時溢出,就是MemoryStream處理的文件可能只有40M或更小時,也會發生OutOfMemory的異常,關於這個問題,終於在老外的一篇文章中得到了解釋,運氣還不錯,可以看看這篇博文:,由於涉及到windows的內存機制,包括內存也,進程的虛擬地址空間等,比較複雜,所以大家看他的文章前,我先和大家簡單的介紹一下頁和進程的虛擬地址:

內存頁:內存頁分為:文件頁和計算頁

內存中的文件頁是文件緩存區,即文件型的內存頁,用於存放文件數據的內存頁(也稱永久頁),作用在於讀寫文件時可以減少對磁盤的訪問,如果它的大小設置的太小,會引起系統頻繁的訪問磁盤,增加磁盤I/O,設置太大,會浪費內存資源。

內存中的計算頁也稱為計算型的內存頁,主要用於存放程序代碼和臨時使用的數據。

進程的虛擬地址:每一個進程被給予它的非常自由的虛擬地址空間。對於32位的進程,地址空間是4G,因為一個32位指針能夠從0x00000000到0xffffffff之間的任意值,這個範圍允許指針從4294967296個值得一個,覆蓋了一個進程得4G範圍,對於64位進程,地址空間是16eb因為一個64位指針能夠指向18,446,744,073,709,551,616個值中的一個,覆蓋一個進程的16eb範圍,這是十分寬廣的範圍,上述概念都在自windows核心編程這本書,其實這本書對於我們程序員來說很重要,對於內存的操作,本人也是小白。

四、MemoryStream的構造函數

1、MemoryStream()

MemoryStream允許不帶參數的構造

2、MemoryStream(byte[] byte)

Byte數組是包含了一定數據的byte數組,這個構造很重要,初學者或者用的不是很多的程序員會忽略這個構造函數導致後面讀取或寫入數據時發現MemoryStream中沒有byte數據,會導致很鬱悶的感覺,大家注意一下就行,有時候也可能無需這樣,因為很多方法返回值已經是MemoryStream了。

3、MemoryStream(int capacity)

這個是重中之重,為什麼這麼說呢?我在本文探討關於OutMemory異常中也提到了,如果你想額外提高MemoryStream的吞吐量,也只能靠這個方法提升一定的吞吐量,最多也只能到int.Max,這個方法也是解決OutOfMemory的一個可行方案。

4、MemoryStream(byte[] byte,bool writeable)

writeable參數定義該流是否可寫

5、MemoryStream(byte[] byte,int index,int count)

index:參數定義從byte數組中的索引index

count:參數是獲取的數據量的個數

6、MemoryStream(byte[] byte,int index,int count,bool writeable,bool publiclyVisible)

publiclyVisible:參數表示true可以啟用GetBuffer方法,它返回無符號字節數組,流從該數組創建,否則為false。(大家一定覺得這個很難理解,別急,下面的方法中我會詳細的講一下這個東西)

五、MemoryStream的屬性

 Memory的屬性大致都是和其父類很相似,這些功能在我的這篇文章中已經詳細討論過,所以我簡單列舉以下其屬性:

 

 其獨有的屬性:

Capacity:這個前文其實已經提及,它表示該流的可支配容量(字節),非常重要的一個屬性。

六、MemoryStream的方法

對於重寫的方法,這裏不再重複說明,大家可以去看一下

 以下是MemoryStream獨有的方法

1、virtual byte[] GetBuffer()

這個方法使用時需要小心,因為這個方法返回無符號字節數組,也就是說,即使我只輸入幾個字符例如“HellowWorld”我們只希望返回11個數據就行,可是這個方法會把整個緩衝區的數據,包括那些已經分配但是實際上沒有用到的字符數據都返回回來了,如果想啟用這個方法那必須使用上面最後一個構造函數,將publiclyVisible屬性設置成true就行,這也是上面那個構造函數的錯用所在。

2、virtual void WriteTo(Stream stream)

這個方法的目的其實在本文開始的時候討論性能問題時已經指出,MemoryStream常用起中間流的作用,所以讀寫在處理完后將內存吸入其他流中。

七、示例:

1、XmlWriter中使用MemoryStream

 1         public static void UseMemoryStreamInXmlWriter()
 2         {
 3             var ms = new MemoryStream();
 4             using (ms)
 5             {
 6                 //定義一個XmlWriter
 7                 using (XmlWriter writer= XmlWriter.Create(ms))
 8                 {
 9                     //寫入xml頭
10                     writer.WriteStartDocument(true);
11                     //寫入一個元素
12                     writer.WriteStartElement("Content");
13                     //為這個元素增加一個test屬性
14                     writer.WriteStartAttribute("test");
15                     //設置test屬性的值
16                     writer.WriteValue("萌萌小魔王");
17                     //釋放緩衝,這裏可以不用釋放,但是在實際項目中可能要考慮部分釋放對性能帶來的提升
18                     writer.Flush();
19                     Console.WriteLine($"此時內存使用量為:{GC.GetTotalMemory(false)/1024}KB,該MemoryStream已使用容量為:{Math.Round((double)ms.Length,4)}byte,默認容量為:{ms.Capacity}byte");
20                     Console.WriteLine($"重新定位前MemoryStream所在的位置是{ms.Position}");
21                     //將流中所在當前位置往後移動7位,相當於空格
22                     ms.Seek(7, SeekOrigin.Current);
23                     Console.WriteLine($"重新定位后MemoryStream所存在的位置是{ms.Position}");
24                     //如果將流所在的位置設置位如下示的位置,則XML文件會被打亂
25                     //ms.Position = 0;
26                     writer.WriteStartElement("Content2");
27                     writer.WriteStartAttribute("testInner");
28                     writer.WriteValue("萌萌小魔王2");
29                     writer.WriteEndElement();
30                     writer.WriteEndElement();
31                     //再次釋放
32                     writer.Flush();
33                     Console.WriteLine($"此時內存使用量為:{GC.GetTotalMemory(false) / 1024}KB,該MemoryStream已使用容量為:{Math.Round((double)ms.Length, 4)}byte,默認容量為:{ms.Capacity}byte");
34                     //建立一個FileStream 文件創建目的地是f:\test.xml
35                     var fs=new FileStream(@"f:\test.xml",FileMode.OpenOrCreate);
36                     using (fs)
37                     {
38                         //將內存流注入FileStream
39                         ms.WriteTo(fs);
40                         if (ms.CanWrite)
41                         {
42                             //釋放緩衝區
43                             fs.Flush();
44                         }
45                     }
46                     Console.WriteLine();
47                 }
48             }
49         }

運行結果:

 

 咱看一下XML文本是什麼樣的?

 

 2、自定義處理圖片的HttpHandler

有時項目里我們必須將圖片進行一定的操作,例如:水印,下載等,為了方便和管理我們可以自定義一個HttpHandler來負責這些工作

後台代碼:

 1     public class ImageHandler : IHttpHandler
 2     {
 3         /// <summary>
 4         /// 實現IHttpHandler接口中ProcessRequest方法
 5         /// </summary>
 6         /// <param name="context"></param>
 7         public void ProcessRequest(HttpContext context)
 8         {
 9             context.Response.Clear();
10             //得到圖片名
11             var imageName = context.Request["ImageName"] ?? "小魔王";
12             //得到圖片地址
13             var stringFilePath = context.Server.MapPath($"~/Image/{imageName}.jpg");
14             //聲明一個FileStream用來將圖片暫時放入流中
15             FileStream stream=new FileStream(stringFilePath,FileMode.Open);
16             using (stream)
17             {
18                 //通過GetImageFromStream方法將圖片放入Byte數組中
19                 var imageBytes = GetImageFromStream(stream, context);
20                 //上下文確定寫道客戶端時的文件類型
21                 context.Response.ContentType = "image/jpeg";
22                 //上下文將imageBytes中的數組寫到前端
23                 context.Response.BinaryWrite(imageBytes);
24             }
25         }
26 
27         public bool IsReusable => true;
28 
29         /// <summary>
30         /// 將流中的圖片信息放入byte數組后返回該數組
31         /// </summary>
32         /// <param name="stream">文件流</param>
33         /// <param name="context">上下文</param>
34         /// <returns></returns>
35         private byte[] GetImageFromStream(FileStream stream, HttpContext context)
36         {
37             //通過Stream到Image
38             var image = Image.FromStream(stream);
39             //加上水印
40             image = SetWaterImage(image, context);
41             //得到一個ms對象
42             MemoryStream ms = new MemoryStream();
43             using (ms)
44             {
45                 //將圖片保存至內存流
46                 image.Save(ms,ImageFormat.Jpeg);
47                 byte[] imageBytes = new byte[ms.Length];
48                 ms.Position = 0;
49                 //通過內存流放到imageBytes
50                 ms.Read(imageBytes, 0, imageBytes.Length);
51                 //ms.Close();
52                 //返回imageBytes
53                 return imageBytes;
54             }
55         }
56 
57         private Image SetWaterImage(Image image, HttpContext context)
58         {
59             Graphics graphics = Graphics.FromImage(image);
60             Image waterImage = Image.FromFile(context.Server.MapPath("~/Image/logo.jpg"));
61             graphics.DrawImage(waterImage, new Point { X = image.Size.Width - waterImage.Size.Width, Y = image.Size.Height - waterImage.Size.Height });
62             return image;
63         }
64     }

別忘了,還要再web.config中進行配置,如下:

 

 這樣前台就能使用了

 

 讓我們來看一下輸出結果:

 

 哈哈,還不錯。

好了,MemoryStream相關的知識就先分享到這裏了。同志們,再見!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

蘋果傳將攜手韓廠研發電動車用電池

蘋果公司持續擴大業務範圍,除新成立的蘋果能源(Apple Energy)成功取得售電許可外,市場上關注度十足的蘋果電動車專案「泰坦計畫」(Project Titan)也時常傳出新消息。近期傳言蘋果將與南韓某企業合作,運用該南韓公司的電池專利,攜手開發電動車用電池。

根據日本蘋果情報網站iPhone Mania、南韓媒體ET News 等報導,蘋果看上某家南韓廠商所取得的鋰電池專利,打算與該廠合作開發電動車用電池。被看上的鋰電池專利技術,電池中央部位採中空設計,可使空氣流通來冷卻電池,等同降低冷卻系統的需求,騰出更多空間來增加電池容量。

日、韓媒體並未披露可能將與蘋果合作的韓廠名稱,但美國MacRumors 透剁歐洲專利局得知,這款「中央中空」的電池是由一家稱為Orange Power 的南韓廠商取得。該廠係一小廠,員工人數僅33人,其中多數為研發人員。

蘋果電動車計畫自曝光以來即備受矚目,但至今仍然只聞樓梯響。據了解,目前共有約1,000人參與蘋果電動車企劃,且蘋果已在柏林設立秘密開發實驗室。MoneyDJ引述The Information網站的說法,表示蘋果電動車可能在2021年亮相;但也有分析師認為,蘋果電動車可能會步上蘋果電視的後塵,胎死腹中。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

PostgreSQL空間數據庫創建備份恢復(PostGIS vs ArcGIS)

梯子

PostGIS

創建

安裝就不必介紹了,windows下使用安裝工具Application Stack Builder,選擇空間擴展PostGIS即可自動安裝

然後新建庫后,在庫中執行以下語句創建控件擴展

CREATE EXTENSION postgis

也可以創建數據庫時選擇postgis的模板庫創建

create database postgisdb template postgis_template;

新建數據庫后添加postgis擴展後會發現庫內public模式下函數序列觸發器等都會增加一些postgis相關功能
然後就可以通過PostGIS Shapefile and DBF Loader工具導入shp數據

備份

postgersql的備份恢復主要有

  1. 增量備份和基於時間點恢復(RITR)
  2. pg_dump和pg_dumpall進行轉儲,從SQL轉儲文件恢復
  3. 文件系統級別備份

這裏我們使用簡單,容易掌握的pg_dump命令,一般在安裝目錄bin下
pg_dump備份單庫,不導出角色和表空間相關信息

pg_dump -h localhost -U postgres postgisdb > D:\backup\postgisdb.bak

有一些參數選項可以參考(很多,具體不列了,執行help可以查看到)

pg_dump --help
恢復

恢復可以使用psql

psql -h localhost -U postgres -d postgisdb2 < D:\backup\postgisdb.bak

恢復時可以指定不同的數據庫,如果pg_dump時-C創建數據庫,那也可以不用先新建數據庫

postgis庫的恢復備份還是挺簡單的,所有的東西都在public下

ArcGIS

創建

ArcGIS要連接到postgresql,需要將postgresql安裝目錄lib下的libeay32.dll、libiconv-2.dll、libintl-8.dll、libpq.dll 和 ssleay32.dll拷貝到ArcGIS Desktop的安裝目錄bin下
將ArcGIS Desktop目錄DatabaseSupport\PostgreSQL下的st_geometry.dll拷貝到postgresql的lib下

使用ArcGIS工具箱中Create Enterprise Geodatabase工具創建SDE,完事後會在創建一個sde登陸角色並在庫中創建一個sde模式,包含諸多函數序列管理表等。(注意:ArcGIS雖然可以在系統庫postgres中創建SDE擴展,然並連不上,ArcGIS不允許連接訪問系統數據庫

然後ArcGIS可以連接該數據庫,並且進行空間數據管理操作。(注意:默認ArcGIS創建空間數據,只能創建在和登陸用戶同名的模式下

備份

我們可以向上面PostGIS備份恢復一樣,直接備份整個庫

恢復

如果恢復至同名數據庫,像上面恢復是沒有問題的
但如果數據庫改名了,則會有驚喜發生,ArcGIS管理空間報底層gdb_release之類的錯誤,同樣的問題不止恢復庫時,修改數據庫名稱也不像其他庫那麼隨心所欲,以含SDE擴展的庫為模板創建新庫也會有問題

ArcGIS SDE未見文檔介紹內部結構邏輯,只能猜測大概,或不準確,願聞其詳

ArcSDE空間數據創建時會在SDE管理表裡註冊相關信息,比如空間參考,列啊,表的唯一標識等,便於它做數據管理、版本控制

修改庫名后,ArcSDE管理就出問題,主要是一些註冊項,安裝SDE時也會把該庫的信息註冊到SDE管理表中去,所以新庫名,它就不認識了

如果修改了庫名,我們找到以下錶

select * from sde.gdb_items
you need modify : name physicalname path etc...

update sde.sde_table_registry set database_name='testdb';
update sde.sde_column_registry set database_name='testdb';
update sde.sde_geometry_columns set f_table_catalog='testdb';
update sde.sde_raster_columns set database_name='testdb';
update sde.sde_layers set database_name='testdb';

然後就一切正常

當然我們建議不輕易改庫名

這就是商業軟件,足夠強大不夠靈活,封裝和靈活總會互相博弈

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

Go 多變量賦值時注意事項

說到多變量賦值時,先計算所有相關值,然後再從左到右依次賦值,但是這個規則不適用於python
我們來看一例:

package main

import "fmt"

func main() {
    data, i := [3]string{"喬幫主","慕容復","鳩摩智"}, 0
    i, data[i] = 2, "枯榮大師"
    fmt.Println(i, data)
}

輸出結果:

2 [枯榮大師 慕容復 鳩摩智]  

有的朋友會認為,結果不應該是這樣么?(但是python下輸出的結果卻是下面的)?

2 [喬幫主 慕容復 枯榮大師]

事實並如此,我們來看賦值順序這段的理解:

1     data, i := [3]string{"喬幫主","慕容復","鳩摩智"}, 0
2     i, data[i] = 2, "枯榮大師" //注意原則:先計算所有相關值,然後再從左到右依次賦值
3     // 這裏變量i 的順序其實是(i = 0,因為上一行的變量i是0) -> (然後 i = 2), (data[i] 此時取的值是data[0],而不是data[2],也就是data[0] = 枯榮大師)
4     fmt.Println(i, data) //所以這裏最終 輸出 i=2,[枯榮大師 慕容復 鳩摩智]

同樣的多變量賦值卻不適用於python.

data,i=["喬幫主", "慕容復", "鳩摩智"],0
i, data[i] = 2, "枯榮大師" # 注意這裏data[i] 已經是 data[2]了,即data[2]="枯榮大師"
print(i,data) # 輸出 2 ['喬幫主', '慕容復', '枯榮大師']

另外:我們要注意重新賦值與定義新同名變量的區別:再看一例:

package main

func main() {
    name := "喬幫主"
    println(&name)
    name, age := "鳩摩智", 30 // 重新賦值: 與前 name 在同層次的代碼塊中,且有新的變量被定義。
    println(&name, age)    // 通常函數多返回值 err 會被重複使用。
    {
        name, weight := "清風揚", 50 // 定義新同名變量: 不在同層次代碼塊。
        println(&name, weight)
    }
}

輸出:

0xc00002bf78
0xc00002bf78 30
0xc00002bf68 50

注意:因個人機器不同,大家返回的內存引用地址可能和我的不一樣,但是 這步是重點。重點在這裏:
同層級相同變量的賦值,內存地址並不會改變。不同層級相同變量的賦值,其實是定義了一個新同名變量,也就是大家看到的第三行內存地址變了。
接着我們再看有點意思的一段代碼(大家來找茬):

package main

func main() {
    name := "喬幫主"
    println(&name)
    name, age := "鳩摩智", 30 // 重新賦值: 與前 name 在同 層次的代碼塊中,且有新的變量被定義。
    println(&name, age)    // 通常函數多返回值 err 會被重複使用。

    name, weight := 100, 50 // 定義新同名變量: 不在同 層次代碼塊。
    println(&name, weight, age)

}

輸出:

cannot use 100 (type int) as type string in assignment

原因很明顯,因為上面:name := “喬幫主” 已經隱試滴申明了name 是字符串,等同於 var name string. 同層級再次賦值100為整形。這是不允許滴,

但是:重點來了,我們稍改下:

package main

func main() {
    name := "喬幫主"
    println(&name)
    name, age := "鳩摩智", 30 // 重新賦值: 與前 name 在同 層次的代碼塊中,且有新的變量被定義。
    println(&name, age)    // 通常函數多返回值 err 會被重複使用。
    {
        name, weight := 100, 50 // 定義新同名變量: 不在同層次代碼塊。
        println(&name, weight, age)
    }
}

區別就是層級發生了變化,因為{}裏面的name已經是新的變量了。
好啦,到此介紹結束了。博友們有關golang變量使用中遇到的各種奇怪的“坑”,請留下寶貴滴足跡,歡迎拍磚留言.

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選