package main
import (
"bufio"
"fmt"
"golang.org/x/net/html/charset"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"html/template"
"io"
"net/http"
"os"
)
func main() {
http.HandleFunc("/", helloHandleFunc)
http.ListenAndServe(":8080", nil)
}
func determineEncode(filepath string) encoding.Encoding {
//读取文件
file, err := os.Open(filepath)
if err != nil {
fmt.Println("读取错误:", err)
return nil
}
defer file.Close()
bytes, err := bufio.NewReader(file).Peek(1024)
if err != nil {
panic(err)
}
// 读取ANSI类型的文件,会判断name为"windows-1252",直接用这种编码解析中文会乱码,应用gbk
determineEncoding, name, _ := charset.DetermineEncoding(bytes, "text/plain")
if name == "windows-1252" {
return simplifiedchinese.GBK
}
return determineEncoding
}
func helloHandleFunc(w http.ResponseWriter, r *http.Request) {
//文件目录
str := "D:/AStudy/reader/test.txt"
//判断编码类型
e := determineEncode(str)
//打开文件
file, err := os.Open(str)
if err != nil {
fmt.Println("读取错误:", err)
return
}
defer file.Close()
//按照文件编码格式构造读取方式
reader := transform.NewReader(file, e.NewDecoder())
//读取文件内容
content := bufio.NewReader(reader)
//内容拆分成行
var body []string
for {
hang, _, err := content.ReadLine()
if err != nil && err != io.EOF {
fmt.Println("读取错误:", err)
return
}
body = append(body, string(hang))
//最后一行结束读取
if err == io.EOF {
break
}
}
// 获取模板绝对路径
wd, err := os.Getwd()
if err != nil {
fmt.Println("读取根工作目录错误:", err)
}
//解析模板
tmpl, err := template.ParseFiles(wd + "/play/fenghe.html")
if err != nil {
fmt.Println("解析模板错误:", err)
return
}
//渲染模板
tmpl.Execute(w, body)
}
模板如图
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>(102条消息) 小白也能看懂的go进阶开发详解title>
<link href="https://g.csdnimg.cn/static/logo/favicon32.ico" rel="shortcut icon" type="image/x-icon">
<style>
.content{
position: absolute;
left: 380px;
top:90px;
height: 420px;
width: 830px;
overflow-y: scroll;
padding-right: 90px;
font-size: 15px;
}
p {
white-space: pre-line;
}
style>
head>
<body>
<div class="main">
<img title="网址" src="https://img2.doubanio.com/view/status/raw/public/9848b12256c180f.webp" width="100%" style="position: fixed;z-index: -1;">
<div class="content">
{{range .}}
<p>{{.}}p>
{{end}}
div>
div>
body>
html>
测试访问 http://127.0.0.1:8080/ 最终的展示效果如图:
搭配浏览器自带的CTRL+F全局搜索真的绝,上班看小说摸鱼低配版。编码方式不一样真的折磨人,搜又搜不到
由控制台输入文件路径,避免每次切换都要重启目录
//文件目录
//str := "D:/AStudy/reader/AA压箱底/test.txt"
//Scanln会将空格当作字符串分隔符,读取含空格的文件名会出错
//var str string
//_, _ = fmt.Scanln(&str)
//将空格分隔的值依次存放到后续的参数内,读遇到换行符后读取结束
//可行的空格1
//reader1 := bufio.NewReader(os.Stdin)
设置结束字符
//line, _, err := reader1.ReadLine()
//if err != nil {
// fmt.Println(err)
// return
//}
//str := string(line)
//可行的空格2
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
str := strings.ToLower(scanner.Text())
fmt.Printf("正在读取文件:%s", str)
但这样每次还要打开文件夹去找文件的目录再复制粘贴,也很麻烦。
直接上传文件。因为之前想尝试动态路由直接解析,所以换成了gin框架,不过目录层级太多了很麻烦,还是改用gin框架进行html的渲染
package main
import (
"bufio"
"fmt"
"github.com/gin-gonic/gin"
"golang.org/x/net/html/charset"
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io"
"net/http"
"os"
)
func main() {
r := gin.Default()
r.LoadHTMLGlob("templates/*") //html模板的路径
r.Static("/static", "./static")
r.GET("/", UploadHandleFunc)
r.POST("/", GetStoryHandleFunc)
r.Run(":80")
}
func UploadHandleFunc(c *gin.Context) {
c.HTML(http.StatusOK, "upload.html", nil)
}
func GetStoryHandleFunc(c *gin.Context) {
// 上传文件
file, err := c.FormFile("f1")
if err != nil {
fmt.Println("determineEncode 上传文件错误:", err)
//不处理,默认读取旧文
} else {
// 上传文件到指定的目录
c.SaveUploadedFile(file, "playv2/test.txt")
}
//读取暂存文件
body := helloHandleFunc(c.Writer, c.Request)
//渲染
c.HTML(http.StatusOK, "fenghe.html", gin.H{
"body": body,
})
}
func helloHandleFunc(w http.ResponseWriter, r *http.Request) []string {
//暂存文件目录
//s1, err := os.Getwd()
//if err != nil {
// fmt.Println("helloHandleFunc 获取项目根路径错误:", err)
// return nil
//}
//str := fmt.Sprintf("%s/playv2/test.txt", strings.Replace(s1, "\\", "/", -1))
str := "./playv2/test.txt"
//判断编码类型
e := determineEncode(str)
//打开文件
file, err := os.Open(str)
if err != nil {
fmt.Println("helloHandleFunc 打开错误:", err)
return nil
}
defer file.Close()
//按照文件编码格式构造读取方式
reader := transform.NewReader(file, e.NewDecoder())
//读取文件内容
content := bufio.NewReader(reader)
//内容拆分成行
var body []string
for {
hang, _, err := content.ReadLine()
if err != nil && err != io.EOF {
fmt.Println("helloHandleFunc 读取错误:", err)
return nil
}
body = append(body, string(hang))
//最后一行结束读取
if err == io.EOF {
break
}
}
return body
}
func determineEncode(str string) encoding.Encoding {
//打开文件
file, err := os.Open(str)
if err != nil {
fmt.Println("determineEncode 打开错误:", err)
return nil
}
defer file.Close()
//读取文件
bytes, err := bufio.NewReader(file).Peek(1024)
if err != nil && err != io.EOF {
fmt.Println("determineEncode 读取错误:", err)
panic(err)
}
// 读取ANSI类型的文件,会判断name为"windows-1252",用这种编码解析会乱码,应用gbk
determineEncoding, name, _ := charset.DetermineEncoding(bytes, "text/plain")
if name == "windows-1252" {
return simplifiedchinese.GBK
}
return determineEncoding
}
determineEncode判断文件编码和helloHandleFunc读取文件这两个函数小改了一下。
① determineEncode主要是在读取文件时err判断那里修复一个bug:文件如果过小读不了1024字节会报EOF,虽然小说一般不会低于这个长度,但还是严谨一点 err != io.EOF
② helloHandleFunc增加了一个返回值,因为改用gin框架进行html渲染了;获取文件名写死了,因为上传的时候暂存了一下
html模板也小改了下
{{range .body}}
上面是最终的结果,下面为摸索过程及参考文献
package main
import (
"bufio"
"fmt"
"html/template"
"io"
"net/http"
"os"
)
func main() {
http.HandleFunc("/", helloHandleFunc)
http.ListenAndServe(":8080", nil)
}
func helloHandleFunc(w http.ResponseWriter, r *http.Request) {
//读取文件
content, err := os.Open("D:/AStudy/reader/导出/test.txt")
if err != nil {
fmt.Println("读取错误:", err)
}
defer content.Close()
//文件内容拼接成html
hangs := bufio.NewReader(content)
var body []string
for {
hang, err := hangs.ReadString('\n')
//fmt.Printf(hang)
body = append(body, hang)
if err == io.EOF {
break
}
}
// 生成html
// 不支持相对路径,需要使用绝对路径
wd, err := os.Getwd()
if err != nil {
fmt.Println("读取根工作目录错误:", err)
}
//解析模板
tmpl, err := template.ParseFiles(wd + "/play/testout.html") //不支持相对路径,需要使用绝对路径
if err != nil {
fmt.Println("解析模板错误:", err)
}
//渲染模板
tmpl.Execute(w, body)
}
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>testtitle>
head>
<body>
<div class="main">
{{range .}}
<p>{{.}}p>
{{end}}
div>
body>
html>
访问测试 http://127.0.0.1:8080/
读取txt 优化读取txt 生成html html模板路径 如何访问
Q1:背景失败(200但不显示,猜测是加载顺序的问题 https://www.cnblogs.com/ttmdl/articles/6829569.html
Q2:后来发现只有网络地址不会出错,百度知道、QQ、微信、微博都不能访问,上传到豆瓣可以获得外链
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>(102条消息) 小白也能看懂的go进阶开发详解title>
<link href="https://g.csdnimg.cn/static/logo/favicon32.ico" rel="shortcut icon" type="image/x-icon">
<style>
.content{
position: absolute;
left: 380px;
top:90px;
height: 420px;
width: 830px;
overflow-y: scroll;
padding-right: 90px;
font-size: 15px;
}
p {
white-space: pre-line;
}
style>
head>
<body>
<div class="main">
<img title="网址" src="https://img2.doubanio.com/view/status/raw/public/9848b12256c180f.webp" width="100%" style="position: fixed;z-index: -1;">
<div class="content">
{{range .}}
<p>{{.}}p>
{{end}}
div>
div>
body>
html>
乱码,发现go解析文件默认utf8
了解BOM及编码
将文件编码转换为 GB18030 编码 ,不太行,而且这样还得解析/r/n,还原再遍历输出很麻烦,没啥用
Why?需要在读取文件时指定对应编码方式
How?如何指定呢
根本不行,从java获取灵感
试下能不能判断编码格式
/net/html解析网页编码,/text网页对应编码格式转为utf-8
是不是没指定contenttype默认解析网页啊
用mahonia.NewDecoder(“gbk”)转换呢
func determineEncodeing(r io.Reader) encoding.Encoding {
bytes, err := bufio.NewReader(r).Peek(1024)
if err != nil {
panic(err)
}
//
determineEncoding, _, _ := charset.DetermineEncoding(bytes, "text/plain")
return determineEncoding, name
}
// 但是读不了ANSI
func helloHandleFunc(w http.ResponseWriter, r *http.Request) {
//读取文件
file, err := os.Open("D:/AStudy/reader/AA压箱底/《剑似生平》眉如黛.txt")
if err != nil {
fmt.Println("读取错误:", err)
return
}
defer file.Close()
//判断文件编码类型
e := determineEncodeing(file)
//转换为utf-8,并读取字符
var body []string
utf8Reader := transform.NewReader(file, e.NewDecoder())
hangs := bufio.NewReader(utf8Reader)
//内容拆分成行
for {
hang, _, err := hangs.ReadLine()
if err != nil && err != io.EOF {
fmt.Println("读取错误:", err)
return
}
body = append(body, string(hang))
//最后一行结束读取
if err == io.EOF {
break
}
}
// 获取模板绝对路径
wd, err := os.Getwd()
if err != nil {
fmt.Println("读取根工作目录错误:", err)
}
//解析模板
tmpl, err := template.ParseFiles(wd + "/play/fenghe.html")
if err != nil {
fmt.Println("解析模板错误:", err)
return
}
//渲染模板
tmpl.Execute(w, body)
}
utf-8 通过
utf-16通过
utf-16 LE通过
ANSI 按照Windows 1252解析全文乱码
据说windows-1252是ANSI的正确名称
其实ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码。你的美国同事Bob的系统中ANSI编码其实是ASCII编码(ASCII编码不能表示汉字,所以汉字为乱码),而你的系统中(“汉字”正常显示)ANSI编码其实是GBK编码,而韩文系统中(“한국어”正常显示)ANSI编码其实是EUC-KR编码。
尝试下用 mahonia.NewDecoder(“GBK”) 能不能针对ANSI单独设定编码方式
func determineEncodeing(r io.Reader) (encoding.Encoding, string) {
bytes, err := bufio.NewReader(r).Peek(1024)
if err != nil {
panic(err)
}
// name为"windows-1252"的会乱码,decoder := mahonia.NewDecoder("GBK")会丢失部分文件
determineEncoding, name, _ := charset.DetermineEncoding(bytes, "text/plain")
return determineEncoding, name
}
.......
//判断编码类型
e, s := determineEncodeing(file)
//转换为utf-8,并读取字符
var body []string
if s != "windows-1252" {
utf8Reader := transform.NewReader(file, e.NewDecoder())
hangs := bufio.NewReader(utf8Reader)
//内容拆分成行
for {
hang, _, err := hangs.ReadLine()
if err != nil && err != io.EOF {
fmt.Println("读取错误:", err)
return
}
body = append(body, string(hang))
//最后一行结束读取
if err == io.EOF {
break
}
}
} else { // 解析ANSI
reader := bufio.NewReader(file)
decoder := mahonia.NewDecoder("GBK")
//内容拆分成行
for {
hang, err := reader.ReadString('\n')
if err != nil && err != io.EOF {
fmt.Println("读取错误:", err)
return
}
body = append(body, decoder.ConvertString(hang))
//最后一行结束读取
if err == io.EOF {
break
}
}
}
能判断,但不多,读取的文件前87行依旧乱码,且乱成了一行;换了一个文件少前43行。
猜测是解析顺序问题,先转换或许不会丢失
if-else换成了
if s == "windows-1252" {
utf8Reader = transform.NewReader(file, simplifiedchinese.GBK.NewDecoder())
}
然而并没有什么变化,虽然代码短很多
换成GB18030试试,一样少
测试了下直接改txt文件ANSI为utf-8输出文档,用同样的方法测试通过,猜测是文件打开有问题
package main
import (
"fmt"
"testing"
"io/ioutil"
"os"
"path/filepath"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
)
/**
* @Author MengQi
* @Date 2023/6/16 11:18
* @Note
*/
// 读取ANSI(GBK)格式的txt转化为utf-8格式
func TestChange(t *testing.T) {
f, e := os.Open("D:/AStudy/reader/AA压箱底/《剑似生平》眉如黛.txt")
if e != nil {
fmt.Println(e)
return
}
defer f.Close()
reader := transform.NewReader(f, simplifiedchinese.GBK.NewDecoder())
content, err := ioutil.ReadAll(reader)
if err != nil {
fmt.Println(err)
return
}
//输出目录,若不指定则保存在程序所在目录下
dir, file := filepath.Split("test.txt")
newFile := filepath.Join(dir, "new_"+file)
fw, _ := os.Create(newFile)
defer fw.Close()
fw.Write(content)
}
运用相同函数,测试通过。在mian函数中测试却乱码
猜测若不重新打开文章,则读取的数据有缺失;若重新打开则转换无误,根据这点重构方法及handler
func determineEncode(filepath string) encoding.Encoding {
//读取文件
file, err := os.Open(filepath)
if err != nil {
fmt.Println("读取错误:", err)
return nil
}
defer file.Close()
bytes, err := bufio.NewReader(file).Peek(1024)
if err != nil {
panic(err)
}
// 读取ANSI类型的文件,会判断name为"windows-1252",用这种编码解析会乱码,应用gbk
determineEncoding, name, _ := charset.DetermineEncoding(bytes, "text/plain")
if name == "windows-1252" {
return simplifiedchinese.GBK
}
return determineEncoding
}
// 但是读不了ANSI
func helloHandleFunc(w http.ResponseWriter, r *http.Request) {
//文件目录
str := "D:/AStudy/reader/AA压箱底/《剑似生平》眉如黛.txt"
//判断编码类型
e := determineEncode(str)
//打开文件
file, err := os.Open(str)
if err != nil {
fmt.Println("读取错误:", err)
return
}
defer file.Close()
//按照文件编码格式构造读取方式
reader := transform.NewReader(file, e.NewDecoder())
//读取文件内容
content := bufio.NewReader(reader)
//内容拆分成行
var body []string
for {
hang, _, err := content.ReadLine()
if err != nil && err != io.EOF {
fmt.Println("读取错误:", err)
return
}
body = append(body, string(hang))
//最后一行结束读取
if err == io.EOF {
break
}
}
// 获取模板绝对路径
wd, err := os.Getwd()
if err != nil {
fmt.Println("读取根工作目录错误:", err)
}
//解析模板
tmpl, err := template.ParseFiles(wd + "/play/fenghe.html")
if err != nil {
fmt.Println("解析模板错误:", err)
return
}
//渲染模板
tmpl.Execute(w, body)
}