整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

Go语言从入门到精通-06| Web服务完善之HTM

Go语言从入门到精通-06| Web服务完善之HTML文件支持

面我们实现了一个最简单的Web服务器软件。这个服务器软件很傻,无论你的URL是什么,所有请求都只返回“Hello World!”字符串。而且这个字符串是写死在代码中的。

接下来我们继续完善这个Web服务器软件,今天我们增加对普通静态文件的支持。也就是当用户通过浏览器向该服务器发送请求的时候该软件会从磁盘上读取相应的文件,然后发送给浏览器。本次的完善也是很有限的,只对上次的代码做了很小的改动。这里实现的主要功能是从磁盘读取一个文件的内容,然后封装http响应头后发生给浏览器。因此,这里主要涉及到Go语言文件访问相关的库的使用。最后实现的效果就是在浏览器上显示html文件渲染后的内容:

图1 实现效果图

文件访问库

由于涉及到文件的访问,因此这里先介绍一下文件相关的包。Go语言文件相关的操作在os包里面,其中os.File封装了文件读写相关的操作。如下是os包及File涉及的主要函数和方法,由于篇幅问题,这里只保留的必要的内容:

type File

File代表一个打开的文件对象。

func Open(name string) (file *File, err error)

Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。

func OpenFile(name string, flag int, perm FileMode) (file *File, err error)

OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError。

func (f *File) Read(b []byte) (n int, err error)

Read方法从f中读取最多len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。文件终止标志是读取0个字节且返回值err为io.EOF。

func (f *File) Write(b []byte) (n int, err error)

Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

func (f *File) Close() error

Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。

下面是本文实现的从文件读取数据的方法,在Web服务的主程序中通过调用该方法来从磁盘读取数据。这个方法的输入是文件路径,输出是文件的内容。

图2 文件读取方法实现


细心的同学可能已经发现,我们这里读取数据并没有用File的Read方法,而是用了另外一个包ioutil的ReadAll方法。这里使用ioutil包的方法也是作为一个引子,期望大家更多的了解Go语言提供的库函数。该方法与File的Read方法功能是一样的,但性能上要好一些。

ioutil包是一个io相关的包,提供了对常见io操作的性能优化,该包提供的功能主要包括:

func ReadAll(r io.Reader) ([]byte, error)

从一个io.Reader读取所有数据,并返回一个字节数组

func ReadDir(dirname string) ([]os.FileInfo, error)

从一个目录读取数据,并得到这个目录里的文件对象列表

func ReadFile(filename string) ([]byte, error)

读取指定文件的内容,并返回一个字节数组

关于文件操作的相关介绍本文先到这里,更详细的介绍我们后面专门另起新文介绍。

Web服务修改

Web服务端改动的地方也很少,除了上面介绍的读取文件内容的方法外,在主函数中调整了数据发送方面的代码,其它地方均没有做改动。下面是涉及到的代码片段。

图3 服务端代码修改

如图3所示,这里一共修改了3个地方:

  1. 读取文件(固定的文件),并计算文件的长度
  2. 构造http响应头,这里主要是根据文件大小,调整Content-Length字段
  3. 分别发送响应头和响应体

测试验证

完成上述修改后,我们就可以通过浏览器进行验证了。这里需要具备一个html文件,该文件保存在与服务端相同的路径下面,名称为index.html。该文件的内容如下:

图4 HTML文件内容

如果熟悉html的同学,很清楚是做什么的,就是现实一个红色的“Hello World!”字符串,不了解html的同学也没关系,了解到这里就行。

在服务端运行程序, 浏览器数据地址后回车,可以看到如下内容:

图5 最终效果图


好了,今天先到这,后面文章我们将增加对图片的支持。

?

辑部 发自 凹非寺
量子位 报道 | 公众号 QbitAI

日本疫苗,又双叒上热搜了。这一回还和AI有关。

事情是酱婶的,为了防止疫苗保管失误(辉瑞疫苗要求-80℃保存),日本埼玉县现在引入了一种新的冷冻室检测系统:

△ 摄像头监测冰箱读数(图片来自NHK)

用摄像头盯着冰箱的读数,再用电脑软件识别出来。

当温度超出设定范围后,就会向管理人员发出邮件警报。

△ 电脑识别保管温度(图片来自NHK)

不用天天盯着看,工作人员这下是开心了,但这摄像头读数字的操作被po上网,欢乐的气氛可就不是那么简单了。

这不,微博、推特等社交平台上,网友们都快吵翻了。


△截自微博@英式没品笑话百科

一时笑疯者有之:

嘲讽者有之:这就是工匠精神!

但也有网友替这群日本盆友表达了无奈:这也是现实所迫啊。

事情这就有意思了。

于是,本着科(jiu)学(shi)探(wan)究(er)的精神,我们决定好好研究一番:日本工作人员这波操作,到底是“就这”,还是靠谱。

是愚蠢还是机智?

所谓高手在民间,我们先翻翻评论区,看看网友们都有什么小妙招。

有人就问了:直接从冰箱的温度数据上接出信号它不香吗?

就算设备太老,没有数据输出接口,那在冰箱里内放置热电偶,再将热电偶接入到监测系统中,不也更方便吗?

实在不行,换台带温度监控的冰箱不就得了,疫苗还不配一台新冰箱吗?

那么,事情真的这么简单吗?

其实,不少网友都点出了两个关键字——成本

毕竟说实在的,改造系统并非加装个传感器就完事儿了。

我们稍微汇总一下网友们的观点:

首先冰箱设备可能太旧,如果设备本身不提供数据接口,那么获取数据并不方便,甚至要对设备进行破坏性的改造。

另外在冰箱内伸入热电偶,可能会破坏冰箱口的密封,况且还要在-80℃温度下保证探头高精度工作。

还有一点,冰箱是金属外壳,无线传输数据也不可能。

所以,外接摄像头无疑是一种最简单有效的方式,一种典型的程序员思维。

  1. 摄像头与原系统耦合度低,不仅可以用在这种冰箱上,还可以推广到其他解决方案;
  2. 七段数码管的OCR识别程序已经相当成熟,程序员可能只要一个小时就完成系统的全部改造。

对于这样的看法,不少日本网友表示了认同:

这个办法很聪明,它不需要改造冰箱本身,也就不会破坏系统原来的稳定性。

不过,也有日本网友预感一个崭新的背锅侠已经诞生了。未来一旦出事,原因可能是:

(1)相机坏了;(2)温度计坏了;(3)温度计传感器坏了;(4)监控系统坏了。

别问,问就是福岛经验。

其实挺常见

咳咳……

我们还是先顺着这个思路,去GitHub上搜索一番——在七段数码管OCR识别方面,确实有许多用OpenCV实现的现成项目。其中,一个7年前的数码管OCR项目就已经能达到很高的精度。

另外,国内的AI商用平台上也提供付费OCR识别服务,而且识别的情况比只读取一个冰箱温度要复杂得多。

如此成熟的方案,你猜都被用在了哪里?

其实在国内,变电站表计示数识读方面,也有用类似的方法来替代人工操作。比如已经有巡检机器人配备了读数的技能。

当然,这种场景之下的识别复杂度略高一些,因为并不是像日本监测疫苗的摄像头,直接“怼”到了计数器前面,而是有一定的距离。

而正是距离和自然环境等原因,还会出现光线、背景特征难提取等一系列的问题。

但随着计算机视觉技术越来越发达、摄像头成本越来越低,这种解决方案在其他领域也越来越多地被采用。

哦对了,随着我们的进一步好奇心肆虐,我们还发现……

日本的工作人员不是拍脑袋决定的方案啊,引起这次热议的摄像头读温度系统,是一个成熟的、正在售卖的完整商用系统。

这家公司叫做Pacific Systems,官方介绍是这样的:

通过IoT自动化日常监控工作,减轻工作负担!

还醒目地提出安装他家产品的优点:

  • 大幅削减工作时间,减少巡逻、记录数据的工作量。
  • 无论是白天还是晚上,亦或是节假日,都可以不停歇的“工作”。
  • 不联网也能正常工作,获取数据。

而且安装也非常地简单,只需要接入摄像头或其他设备即可,不需要对原来的机器做更改。

还支持各种传感器数据,例如温度、湿度,以及二氧化碳传感器。

而据日本网友透露,这么一套设备,价格从19.8万日元起,也就是1万元人民币左右。

好啦,事情的前因后果,传送完毕。

现在,你觉得日本埼玉县的这种方法是愚蠢还是机智呢?

参考链接:
[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 · 头条号签约

关注我们,第一时间获知前沿科技动态

注天善智能↑,走好数据之路

欢迎关注天善智能微信公众号,我们是专注于商业智能BI,大数据,数据分析领域的垂直社区。

对商业智能BI、大数据分析挖掘、机器学习,python,R等数据领域感兴趣的同学加微信:tstoutiao,邀请你进入头条数据爱好者交流群,数据爱好者们都在这儿。


Emoji表情包天气数据可视化

用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)

刚开始的时候走了冤枉路,写了一大段白花花的无用代码!

####

#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,肯定自己脑抽筋了!

后来换个思路,过段 弃用了RCrul,转投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)

#清晰脏数据:unique(mynewdata$state) happy<-c("晴","阵雨~晴","多云转晴","多云~晴","雷阵雨~晴","阴~晴","霾~晴","浮尘~晴") depressed<-c("霾","阴","多云","晴~多云","霾~多云","晴~霾","多云~霾","阵雨转多云","多云转阴","阴~多云","多云~阴","晴~阴","阵雨~多云","小雨~多云","小雨~阴","霾~雾","小雪~阴","阴~小雪","小雨~雨夹雪") angry<-c("小雨","雨夹雪","小雪","雷阵雨","阵雨","中雨","小到中雨","雷阵雨~阴","多云~雷阵雨","阴~雷阵雨","霾~雷阵雨","多云~阵雨","晴~阵雨","阴~小雨","阵雨~小雨") Terrified<-c("中到大雨","暴雨","雷阵雨~中到大雨")

#创建新变量(主要是将诸多天气类型进行归类):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"})

#创建时间与日期变量: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:/数据可视化/R/R语言学习笔记/可视化/ggplot2/商务图表")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()

这个是图二上面的背景小图,从网上找的,嵌入代码里的,没有P图哦.

个人简介:


转自微信公众号:EasyCharts

对商业智能BI、大数据分析挖掘、机器学习,python,R等数据领域感兴趣同学加微信:tstoutiao,邀请您加入头条数据爱好者交流群,数据爱好者们都在这儿。