面我們實(shí)現(xiàn)了一個(gè)最簡(jiǎn)單的Web服務(wù)器軟件。這個(gè)服務(wù)器軟件很傻,無論你的URL是什么,所有請(qǐng)求都只返回“Hello World!”字符串。而且這個(gè)字符串是寫死在代碼中的。
接下來我們繼續(xù)完善這個(gè)Web服務(wù)器軟件,今天我們?cè)黾訉?duì)普通靜態(tài)文件的支持。也就是當(dāng)用戶通過瀏覽器向該服務(wù)器發(fā)送請(qǐng)求的時(shí)候該軟件會(huì)從磁盤上讀取相應(yīng)的文件,然后發(fā)送給瀏覽器。本次的完善也是很有限的,只對(duì)上次的代碼做了很小的改動(dòng)。這里實(shí)現(xiàn)的主要功能是從磁盤讀取一個(gè)文件的內(nèi)容,然后封裝http響應(yīng)頭后發(fā)生給瀏覽器。因此,這里主要涉及到Go語言文件訪問相關(guān)的庫的使用。最后實(shí)現(xiàn)的效果就是在瀏覽器上顯示html文件渲染后的內(nèi)容:
圖1 實(shí)現(xiàn)效果圖
由于涉及到文件的訪問,因此這里先介紹一下文件相關(guān)的包。Go語言文件相關(guān)的操作在os包里面,其中os.File封裝了文件讀寫相關(guān)的操作。如下是os包及File涉及的主要函數(shù)和方法,由于篇幅問題,這里只保留的必要的內(nèi)容:
type File
File代表一個(gè)打開的文件對(duì)象。
func Open(name string) (file *File, err error)
Open打開一個(gè)文件用于讀取。如果操作成功,返回的文件對(duì)象的方法可用于讀取數(shù)據(jù);對(duì)應(yīng)的文件描述符具有O_RDONLY模式。如果出錯(cuò),錯(cuò)誤底層類型是*PathError。
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
OpenFile是一個(gè)更一般性的文件打開函數(shù),大多數(shù)調(diào)用者都應(yīng)用Open或Create代替本函數(shù)。它會(huì)使用指定的選項(xiàng)(如O_RDONLY等)、指定的模式(如0666等)打開指定名稱的文件。如果操作成功,返回的文件對(duì)象可用于I/O。如果出錯(cuò),錯(cuò)誤底層類型是*PathError。
func (f *File) Read(b []byte) (n int, err error)
Read方法從f中讀取最多l(xiāng)en(b)字節(jié)數(shù)據(jù)并寫入b。它返回讀取的字節(jié)數(shù)和可能遇到的任何錯(cuò)誤。文件終止標(biāo)志是讀取0個(gè)字節(jié)且返回值err為io.EOF。
func (f *File) Write(b []byte) (n int, err error)
Write向文件中寫入len(b)字節(jié)數(shù)據(jù)。它返回寫入的字節(jié)數(shù)和可能遇到的任何錯(cuò)誤。如果返回值n!=len(b),本方法會(huì)返回一個(gè)非nil的錯(cuò)誤。
func (f *File) Close() error
Close關(guān)閉文件f,使文件不能用于讀寫。它返回可能出現(xiàn)的錯(cuò)誤。
下面是本文實(shí)現(xiàn)的從文件讀取數(shù)據(jù)的方法,在Web服務(wù)的主程序中通過調(diào)用該方法來從磁盤讀取數(shù)據(jù)。這個(gè)方法的輸入是文件路徑,輸出是文件的內(nèi)容。
圖2 文件讀取方法實(shí)現(xiàn)
細(xì)心的同學(xué)可能已經(jīng)發(fā)現(xiàn),我們這里讀取數(shù)據(jù)并沒有用File的Read方法,而是用了另外一個(gè)包ioutil的ReadAll方法。這里使用ioutil包的方法也是作為一個(gè)引子,期望大家更多的了解Go語言提供的庫函數(shù)。該方法與File的Read方法功能是一樣的,但性能上要好一些。
ioutil包是一個(gè)io相關(guān)的包,提供了對(duì)常見io操作的性能優(yōu)化,該包提供的功能主要包括:
func ReadAll(r io.Reader) ([]byte, error)
從一個(gè)io.Reader讀取所有數(shù)據(jù),并返回一個(gè)字節(jié)數(shù)組
func ReadDir(dirname string) ([]os.FileInfo, error)
從一個(gè)目錄讀取數(shù)據(jù),并得到這個(gè)目錄里的文件對(duì)象列表
func ReadFile(filename string) ([]byte, error)
讀取指定文件的內(nèi)容,并返回一個(gè)字節(jié)數(shù)組
關(guān)于文件操作的相關(guān)介紹本文先到這里,更詳細(xì)的介紹我們后面專門另起新文介紹。
Web服務(wù)端改動(dòng)的地方也很少,除了上面介紹的讀取文件內(nèi)容的方法外,在主函數(shù)中調(diào)整了數(shù)據(jù)發(fā)送方面的代碼,其它地方均沒有做改動(dòng)。下面是涉及到的代碼片段。
圖3 服務(wù)端代碼修改
如圖3所示,這里一共修改了3個(gè)地方:
測(cè)試驗(yàn)證
完成上述修改后,我們就可以通過瀏覽器進(jìn)行驗(yàn)證了。這里需要具備一個(gè)html文件,該文件保存在與服務(wù)端相同的路徑下面,名稱為index.html。該文件的內(nèi)容如下:
圖4 HTML文件內(nèi)容
如果熟悉html的同學(xué),很清楚是做什么的,就是現(xiàn)實(shí)一個(gè)紅色的“Hello World!”字符串,不了解html的同學(xué)也沒關(guān)系,了解到這里就行。
在服務(wù)端運(yùn)行程序, 瀏覽器數(shù)據(jù)地址后回車,可以看到如下內(nèi)容:
圖5 最終效果圖
好了,今天先到這,后面文章我們將增加對(duì)圖片的支持。
?
輯部 發(fā)自 凹非寺
量子位 報(bào)道 | 公眾號(hào) QbitAI
日本疫苗,又雙叒上熱搜了。這一回還和AI有關(guān)。
事情是醬嬸的,為了防止疫苗保管失誤(輝瑞疫苗要求-80℃保存),日本埼玉縣現(xiàn)在引入了一種新的冷凍室檢測(cè)系統(tǒng):
△ 攝像頭監(jiān)測(cè)冰箱讀數(shù)(圖片來自NHK)
用攝像頭盯著冰箱的讀數(shù),再用電腦軟件識(shí)別出來。
當(dāng)溫度超出設(shè)定范圍后,就會(huì)向管理人員發(fā)出郵件警報(bào)。
△ 電腦識(shí)別保管溫度(圖片來自NHK)
不用天天盯著看,工作人員這下是開心了,但這攝像頭讀數(shù)字的操作被po上網(wǎng),歡樂的氣氛可就不是那么簡(jiǎn)單了。
這不,微博、推特等社交平臺(tái)上,網(wǎng)友們都快吵翻了。
△截自微博@英式?jīng)]品笑話百科
一時(shí)笑瘋者有之:
嘲諷者有之:這就是工匠精神!
但也有網(wǎng)友替這群日本盆友表達(dá)了無奈:這也是現(xiàn)實(shí)所迫啊。
事情這就有意思了。
于是,本著科(jiu)學(xué)(shi)探(wan)究(er)的精神,我們決定好好研究一番:日本工作人員這波操作,到底是“就這”,還是靠譜。
所謂高手在民間,我們先翻翻評(píng)論區(qū),看看網(wǎng)友們都有什么小妙招。
有人就問了:直接從冰箱的溫度數(shù)據(jù)上接出信號(hào)它不香嗎?
就算設(shè)備太老,沒有數(shù)據(jù)輸出接口,那在冰箱里內(nèi)放置熱電偶,再將熱電偶接入到監(jiān)測(cè)系統(tǒng)中,不也更方便嗎?
實(shí)在不行,換臺(tái)帶溫度監(jiān)控的冰箱不就得了,疫苗還不配一臺(tái)新冰箱嗎?
那么,事情真的這么簡(jiǎn)單嗎?
其實(shí),不少網(wǎng)友都點(diǎn)出了兩個(gè)關(guān)鍵字——成本。
畢竟說實(shí)在的,改造系統(tǒng)并非加裝個(gè)傳感器就完事兒了。
我們稍微匯總一下網(wǎng)友們的觀點(diǎn):
首先冰箱設(shè)備可能太舊,如果設(shè)備本身不提供數(shù)據(jù)接口,那么獲取數(shù)據(jù)并不方便,甚至要對(duì)設(shè)備進(jìn)行破壞性的改造。
另外在冰箱內(nèi)伸入熱電偶,可能會(huì)破壞冰箱口的密封,況且還要在-80℃溫度下保證探頭高精度工作。
還有一點(diǎn),冰箱是金屬外殼,無線傳輸數(shù)據(jù)也不可能。
所以,外接攝像頭無疑是一種最簡(jiǎn)單有效的方式,一種典型的程序員思維。
對(duì)于這樣的看法,不少日本網(wǎng)友表示了認(rèn)同:
這個(gè)辦法很聰明,它不需要改造冰箱本身,也就不會(huì)破壞系統(tǒng)原來的穩(wěn)定性。
不過,也有日本網(wǎng)友預(yù)感一個(gè)嶄新的背鍋俠已經(jīng)誕生了。未來一旦出事,原因可能是:
(1)相機(jī)壞了;(2)溫度計(jì)壞了;(3)溫度計(jì)傳感器壞了;(4)監(jiān)控系統(tǒng)壞了。
別問,問就是福島經(jīng)驗(yàn)。
咳咳……
我們還是先順著這個(gè)思路,去GitHub上搜索一番——在七段數(shù)碼管OCR識(shí)別方面,確實(shí)有許多用OpenCV實(shí)現(xiàn)的現(xiàn)成項(xiàng)目。其中,一個(gè)7年前的數(shù)碼管OCR項(xiàng)目就已經(jīng)能達(dá)到很高的精度。
另外,國(guó)內(nèi)的AI商用平臺(tái)上也提供付費(fèi)OCR識(shí)別服務(wù),而且識(shí)別的情況比只讀取一個(gè)冰箱溫度要復(fù)雜得多。
如此成熟的方案,你猜都被用在了哪里?
其實(shí)在國(guó)內(nèi),變電站表計(jì)示數(shù)識(shí)讀方面,也有用類似的方法來替代人工操作。比如已經(jīng)有巡檢機(jī)器人配備了讀數(shù)的技能。
當(dāng)然,這種場(chǎng)景之下的識(shí)別復(fù)雜度略高一些,因?yàn)椴⒉皇窍袢毡颈O(jiān)測(cè)疫苗的攝像頭,直接“懟”到了計(jì)數(shù)器前面,而是有一定的距離。
而正是距離和自然環(huán)境等原因,還會(huì)出現(xiàn)光線、背景特征難提取等一系列的問題。
但隨著計(jì)算機(jī)視覺技術(shù)越來越發(fā)達(dá)、攝像頭成本越來越低,這種解決方案在其他領(lǐng)域也越來越多地被采用。
哦對(duì)了,隨著我們的進(jìn)一步好奇心肆虐,我們還發(fā)現(xiàn)……
日本的工作人員不是拍腦袋決定的方案啊,引起這次熱議的攝像頭讀溫度系統(tǒng),是一個(gè)成熟的、正在售賣的完整商用系統(tǒng)。
這家公司叫做Pacific Systems,官方介紹是這樣的:
通過IoT自動(dòng)化日常監(jiān)控工作,減輕工作負(fù)擔(dān)!
還醒目地提出安裝他家產(chǎn)品的優(yōu)點(diǎn):
而且安裝也非常地簡(jiǎn)單,只需要接入攝像頭或其他設(shè)備即可,不需要對(duì)原來的機(jī)器做更改。
還支持各種傳感器數(shù)據(jù),例如溫度、濕度,以及二氧化碳傳感器。
而據(jù)日本網(wǎng)友透露,這么一套設(shè)備,價(jià)格從19.8萬日元起,也就是1萬元人民幣左右。
好啦,事情的前因后果,傳送完畢。
現(xiàn)在,你覺得日本埼玉縣的這種方法是愚蠢還是機(jī)智呢?
參考鏈接:
[1]https://www3.nhk.or.jp/news/html/20210610/k10013078621000.html
[2]https://weibo.com/2123664205/Kkaymt6V2
[3]https://prtimes.jp/main/html/rd/p/000000046.000061548.html
— 完 —
量子位 QbitAI · 頭條號(hào)簽約
關(guān)注我們,第一時(shí)間獲知前沿科技動(dòng)態(tài)
歡迎關(guān)注天善智能微信公眾號(hào),我們是專注于商業(yè)智能BI,大數(shù)據(jù),數(shù)據(jù)分析領(lǐng)域的垂直社區(qū)。
對(duì)商業(yè)智能BI、大數(shù)據(jù)分析挖掘、機(jī)器學(xué)習(xí),python,R等數(shù)據(jù)領(lǐng)域感興趣的同學(xué)加微信:tstoutiao,邀請(qǐng)你進(jìn)入頭條數(shù)據(jù)愛好者交流群,數(shù)據(jù)愛好者們都在這兒。
用emoji表情來可視化北京2016年度每日天氣狀況!
library(RCurl)library(XML) library(dplyr) library(stringr) library(tidyr) library(plyr) library(rvest) library(ggimage) library(Cairo) library(showtext) library(lubridate)
url<-"http://lishi.tianqi.com/beijing/index.html"myheader <-c("User-Agent"="Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")webpage<-getURL(url,httpheader=myheader)
mymonthlink<-getHTMLLinks(url,externalOnly=TRUE)%>%grep(".*?2016\d{2}.html",.,value=T)
剛開始的時(shí)候走了冤枉路,寫了一大段白花花的無用代碼!
####
#page1<-getURL(mymonthlink[2],.encoding="gbk")
#rd<-iconv(page1,"gbk","utf-8")
#rdhtml<-htmlParse(rd,encoding="UTF-8")
#cesh<-readHTMLList(rdhtml,trim=TRUE,elFun=xmlValue)%>%grep("\d{4}-\d{2}-\d{2}",.,value=T)<br>#cesh<-cesh%>%sub("([a-z])(\()(\\)","",.)
#cesh<-cesh1%>%str_split(',')%>%plyr::ldply(.fun=NULL)
#cesh$V1<-cesh$V1%>%sub("[a-z]\(","",.)%>%as.Date()<br>#names(cesh)<-c("date","high","low","state","wind","index")
####
#以上代碼寫了一半寫不下去了,我有rvest為啥要用RCurl,肯定自己腦抽筋了!
后來換個(gè)思路,過段 棄用了RCrul,轉(zhuǎn)投rvest去了!
mynewdata<-c()for (i in mymonthlink){mymonthdata<-read_html(i,encoding="gbk")%>%html_nodes("div.tqtongji2>ul")%>%html_text(trim=FALSE)%>%str_trim(.,side="right")%>%.[-1]mynewdata<-c(mynewdata,mymonthdata)}mynewdata1<-mynewdatamynewdata<-mynewdata1%>%gsub("\t\t\t|\t|\r\n","",.)%>%str_split(' ')%>%plyr::ldply(.fun=NULL)%>%.[,-2]names(mynewdata)<-c("date","high","low","state","wind","index")mynewdata$date<-as.Date(mynewdata$date)mynewdata$high<-as.numeric(mynewdata$high)mynewdata$low<-as.numeric(mynewdata$low)
#清晰臟數(shù)據(jù):unique(mynewdata$state) happy<-c("晴","陣雨~晴","多云轉(zhuǎn)晴","多云~晴","雷陣雨~晴","陰~晴","霾~晴","浮塵~晴") depressed<-c("霾","陰","多云","晴~多云","霾~多云","晴~霾","多云~霾","陣雨轉(zhuǎn)多云","多云轉(zhuǎn)陰","陰~多云","多云~陰","晴~陰","陣雨~多云","小雨~多云","小雨~陰","霾~霧","小雪~陰","陰~小雪","小雨~雨夾雪") angry<-c("小雨","雨夾雪","小雪","雷陣雨","陣雨","中雨","小到中雨","雷陣雨~陰","多云~雷陣雨","陰~雷陣雨","霾~雷陣雨","多云~陣雨","晴~陣雨","陰~小雨","陣雨~小雨") Terrified<-c("中到大雨","暴雨","雷陣雨~中到大雨")
#創(chuàng)建新變量(主要是將諸多天氣類型進(jìn)行歸類):mynewdata$mode<-NULLmynewdata$mood<-ifelse(mynewdata$state%in% happy,"happy",ifelse(mynewdata$state%in% depressed,"depressed",ifelse(mynewdata$state%in% angry,"angry","Terrified"))) mynewdata <- within(mynewdata,{ mood_code <- NA mood_code[mood=="happy"]<-"1f604" mood_code[mood=="depressed"]<-"1f633" mood_code[mood=="angry"]<-"1f62d" mood_code[mood=="Terrified"]<-"1f621"})
#創(chuàng)建時(shí)間與日期變量:mynewdata$month<-as.numeric(as.POSIXlt(mynewdata$date)$mon+1)mynewdata$monthf<-factor(mynewdata$month,levels=as.character(1:12),labels=c("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"),ordered=TRUE) mynewdata$weekday<-as.POSIXlt(mynewdata$date)$wdaymynewdata$weekdayf<-factor(mynewdata$weekday,levels=rev(0:6),labels=rev(c("Sun","Mon","Tue","Wed","Thu","Fri","Sat")),ordered=TRUE)mynewdata$week <- as.numeric(format(mynewdata$date,"%W"))mynewdata<-ddply(mynewdata,.(monthf),transform,monthweek=1+week-min(week))mynewdata$day<-day(mynewdata$date)
setwd("F:/數(shù)據(jù)可視化/R/R語言學(xué)習(xí)筆記/可視化/ggplot2/商務(wù)圖表")write.table(mynewdata,"historyweather.csv",sep=",",row.names=FALSE)mynewdata<-read.csv("historyweather.csv",stringsAsFactors=FALSE,check.names=FALSE)
圖1的主題:
mytheme<-theme( rect=element_blank(), axis.ticks=element_blank(), text=element_text(face="plain",lineheight=0.9,hjust=0.5,vjust=0.5,size=15), title=element_text(face="plain",lineheight=0.9,hjust=0,vjust=0.5,size=30), axis.title=element_blank(), strip.text=element_text(size=rel(0.8)), plot.margin=unit(c(5,2,5,2),"lines") )
圖一效果:
CairoPNG("emoji1.png",1000,870)
showtext.begin()
ggplot(mynewdata,aes(weekdayf,monthweek,fill=high))+
geom_tile(colour='white')+scale_fill_gradient(low=NA, high=NA,guide=FALSE)+ggtitle("The emoji-weather visualization of beijing in 2016")+scale_y_reverse(breaks=seq(from=6,to=0,by=-1))+ggimage::geom_emoji(aes(image=mood_code),size=.1)+facet_wrap(~monthf ,nrow=3)+
mythemeshowtext.end()
dev.off()
圖二主題:
mytheme2<-theme(
rect=element_blank(),
axis.ticks=element_blank(), text=element_text(face="plain",lineheight=0.9,hjust=0.5,vjust=0.5,size=15), title=element_text(face="plain",lineheight=0.9,hjust=0,vjust=0.5,size=30), axis.title=element_blank(),
strip.text=element_text(size=rel(0.8)),
plot.margin=unit(c(1,1,1,1),"lines")
)
CairoPNG("emoji2.png",1200,1200)
showtext.begin()
ggplot(mynewdata,aes(x=factor(day),y=monthf,fill=high))+geom_tile(colour='white')+expand_limits(y=c(-12,12))+
scale_x_discrete(position=c("bottom"))+
coord_polar(theta="x")+
scale_fill_gradient(low=NA,
high=NA,guide=FALSE)+
ggimage::geom_emoji(aes(image=mood_code),size=.015)+
geom_image(aes(x=0,y=-12),image="weather.png", size=.15)+ggtitle("The emoji-weather visualization of beijing in 2016")+
mytheme2
showtext.end()
dev.off()
這個(gè)是圖二上面的背景小圖,從網(wǎng)上找的,嵌入代碼里的,沒有P圖哦.
個(gè)人簡(jiǎn)介:
轉(zhuǎn)自微信公眾號(hào):EasyCharts
對(duì)商業(yè)智能BI、大數(shù)據(jù)分析挖掘、機(jī)器學(xué)習(xí),python,R等數(shù)據(jù)領(lǐng)域感興趣同學(xué)加微信:tstoutiao,邀請(qǐng)您加入頭條數(shù)據(jù)愛好者交流群,數(shù)據(jù)愛好者們都在這兒。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。