diff --git a/404.html b/404.html new file mode 100644 index 00000000..b5fee1ce --- /dev/null +++ b/404.html @@ -0,0 +1,4 @@ +404 Page not found | raikiriww's blog
High一下!
404
\ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..acd69404 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +blog.raikiriww.net \ No newline at end of file diff --git a/assets/css/stylesheet.css b/assets/css/stylesheet.css new file mode 100644 index 00000000..d80867a6 --- /dev/null +++ b/assets/css/stylesheet.css @@ -0,0 +1,7 @@ +/* + PaperMod v7 + License: MIT https://github.com/adityatelange/hugo-PaperMod/blob/master/LICENSE + Copyright (c) 2020 nanxiaobei and adityatelange + Copyright (c) 2021-2023 adityatelange +*/ +:root{--gap:24px;--content-gap:20px;--nav-width:1024px;--main-width:1024px;--header-height:60px;--footer-height:60px;--radius:8px;--theme:rgb(255, 255, 255);--entry:rgb(255, 255, 255);--primary:rgb(30, 30, 30);--secondary:rgb(108, 108, 108);--tertiary:rgb(214, 214, 214);--content:rgb(31, 31, 31);--hljs-bg:#14111a;--code-bg:rgb(245, 245, 245);--border:rgb(238, 238, 238)}.dark{--theme:rgb(29, 30, 32);--entry:rgb(46, 46, 51);--primary:rgb(218, 218, 219);--secondary:rgb(155, 156, 157);--tertiary:rgb(65, 66, 68);--content:rgb(196, 196, 197);--hljs-bg:rgb(46, 46, 51);--code-bg:rgb(55, 56, 62);--border:rgb(51, 51, 51)}.list{background:var(--code-bg)}.dark.list{background:var(--theme)}*,::after,::before{box-sizing:border-box}html{-webkit-tap-highlight-color:transparent;overflow-y:scroll;-webkit-text-size-adjust:100%;text-size-adjust:100%}a,button,body,h1,h2,h3,h4,h5,h6{color:var(--primary)}body{font-family:-apple-system,BlinkMacSystemFont,segoe ui,Roboto,Oxygen,Ubuntu,Cantarell,open sans,helvetica neue,sans-serif;font-size:18px;line-height:1.6;word-break:break-word;background:var(--theme)}article,aside,figcaption,figure,footer,header,hgroup,main,nav,section,table{display:block}h1,h2,h3,h4,h5,h6{line-height:1.2}h1,h2,h3,h4,h5,h6,p{margin-top:0;margin-bottom:0}ul{padding:0}a{text-decoration:none}body,figure,ul{margin:0}table{width:100%;border-collapse:collapse;border-spacing:0;overflow-x:auto;word-break:keep-all}button,input,textarea{padding:0;font:inherit;background:0 0;border:0}input,textarea{outline:0}button,input[type=button],input[type=submit]{cursor:pointer}input:-webkit-autofill,textarea:-webkit-autofill{box-shadow:0 0 0 50px var(--theme)inset}img{display:block;max-width:100%}.not-found{position:absolute;left:0;right:0;display:flex;align-items:center;justify-content:center;height:80%;font-size:160px;font-weight:700}.archive-posts{width:100%;font-size:16px}.archive-year{margin-top:40px}.archive-year:not(:last-of-type){border-bottom:2px solid var(--border)}.archive-month{display:flex;align-items:flex-start;padding:10px 0}.archive-month-header{margin:25px 0;width:200px}.archive-month:not(:last-of-type){border-bottom:1px solid var(--border)}.archive-entry{position:relative;padding:5px;margin:10px 0}.archive-entry-title{margin:5px 0;font-weight:400}.archive-count,.archive-meta{color:var(--secondary);font-size:14px}.footer,.top-link{font-size:12px;color:var(--secondary)}.footer{max-width:calc(var(--main-width) + var(--gap) * 2);margin:auto;padding:calc((var(--footer-height) - var(--gap))/2)var(--gap);text-align:center;line-height:24px}.footer span{margin-inline-start:1px;margin-inline-end:1px}.footer span:last-child{white-space:nowrap}.footer a{color:inherit;border-bottom:1px solid var(--secondary)}.footer a:hover{border-bottom:1px solid var(--primary)}.top-link{visibility:hidden;position:fixed;bottom:60px;right:30px;z-index:99;background:var(--tertiary);width:42px;height:42px;padding:12px;border-radius:64px;transition:visibility .5s,opacity .8s linear}.top-link,.top-link svg{filter:drop-shadow(0 0 0 var(--theme))}.footer a:hover,.top-link:hover{color:var(--primary)}.top-link:focus,#theme-toggle:focus{outline:0}.nav{display:flex;flex-wrap:wrap;justify-content:space-between;max-width:calc(var(--nav-width) + var(--gap) * 2);margin-inline-start:auto;margin-inline-end:auto;line-height:var(--header-height)}.nav a{display:block}.logo,#menu{display:flex;margin:auto var(--gap)}.logo{flex-wrap:inherit}.logo a{font-size:24px;font-weight:700}.logo a img,.logo a svg{display:inline;vertical-align:middle;pointer-events:none;transform:translate(0,-10%);border-radius:6px;margin-inline-end:8px}button#theme-toggle{font-size:26px;margin:auto 4px}body.dark #moon{vertical-align:middle;display:none}body:not(.dark) #sun{display:none}#menu{list-style:none;word-break:keep-all;overflow-x:auto;white-space:nowrap}#menu li+li{margin-inline-start:var(--gap)}#menu a{font-size:16px}#menu .active{font-weight:500;border-bottom:2px solid}.lang-switch li,.lang-switch ul,.logo-switches{display:inline-flex;margin:auto 4px}.lang-switch{display:flex;flex-wrap:inherit}.lang-switch a{margin:auto 3px;font-size:16px;font-weight:500}.logo-switches{flex-wrap:inherit}.main{position:relative;min-height:calc(100vh - var(--header-height) - var(--footer-height));max-width:calc(var(--main-width) + var(--gap) * 2);margin:auto;padding:var(--gap)}.page-header h1{font-size:40px}.pagination{display:flex}.pagination a{color:var(--theme);font-size:13px;line-height:36px;background:var(--primary);border-radius:calc(36px/2);padding:0 16px}.pagination .next{margin-inline-start:auto}.social-icons{padding:12px 0}.social-icons a:not(:last-of-type){margin-inline-end:12px}.social-icons a svg{height:26px;width:26px}code{direction:ltr}div.highlight,pre{position:relative}.copy-code{display:none;position:absolute;top:4px;right:4px;color:rgba(255,255,255,.8);background:rgba(78,78,78,.8);border-radius:var(--radius);padding:0 5px;font-size:14px;user-select:none}div.highlight:hover .copy-code,pre:hover .copy-code{display:block}.first-entry{position:relative;display:flex;flex-direction:column;justify-content:center;min-height:320px;margin:var(--gap)0 calc(var(--gap) * 2)}.first-entry .entry-header{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.first-entry .entry-header h1{font-size:34px;line-height:1.3}.first-entry .entry-content{margin:14px 0;font-size:16px;-webkit-line-clamp:3}.first-entry .entry-footer{font-size:14px}.home-info .entry-content{-webkit-line-clamp:unset}.post-entry{position:relative;margin-bottom:var(--gap);padding:var(--gap);background:var(--entry);border-radius:var(--radius);transition:transform .1s;border:1px solid var(--border)}.post-entry:active{transform:scale(.96)}.tag-entry .entry-cover{display:none}.entry-header h2{font-size:34px;line-height:1.3}.entry-content{margin:8px 0;color:var(--secondary);font-size:14px;line-height:1.6;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:unset}.entry-footer{color:var(--secondary);font-size:13px}.entry-link{position:absolute;left:0;right:0;top:0;bottom:0}.entry-cover,.entry-isdraft{font-size:14px;color:var(--secondary)}.entry-cover{margin-bottom:var(--gap);text-align:center}.entry-cover img{border-radius:var(--radius);pointer-events:none;width:100%;height:auto}.entry-cover a{color:var(--secondary);box-shadow:0 1px 0 var(--primary)}.page-header,.post-header{margin:24px auto var(--content-gap)}.post-title{margin-bottom:2px;font-size:40px}.post-description{margin-top:10px;margin-bottom:5px}.post-meta,.breadcrumbs{color:var(--secondary);font-size:14px;display:flex;flex-wrap:wrap}.post-meta .i18n_list li{display:inline-flex;list-style:none;margin:auto 3px;box-shadow:0 1px 0 var(--secondary)}.breadcrumbs a{font-size:16px}.post-content{color:var(--content)}.post-content h3,.post-content h4,.post-content h5,.post-content h6{margin:24px 0 16px}.post-content h1{margin:40px auto 32px;font-size:40px}.post-content h2{margin:32px auto 24px;font-size:32px}.post-content h3{font-size:24px}.post-content h4{font-size:16px}.post-content h5{font-size:14px}.post-content h6{font-size:12px}.post-content a,.toc a:hover{box-shadow:0 1px;box-decoration-break:clone;-webkit-box-decoration-break:clone}.post-content a code{margin:auto 0;border-radius:0;box-shadow:0 -1px 0 var(--primary)inset}.post-content del{text-decoration:line-through}.post-content dl,.post-content ol,.post-content p,.post-content figure,.post-content ul{margin-bottom:var(--content-gap)}.post-content ol,.post-content ul{padding-inline-start:20px}.post-content li{margin-top:5px}.post-content li p{margin-bottom:0}.post-content dl{display:flex;flex-wrap:wrap;margin:0}.post-content dt{width:25%;font-weight:700}.post-content dd{width:75%;margin-inline-start:0;padding-inline-start:10px}.post-content dd~dd,.post-content dt~dt{margin-top:10px}.post-content table{margin-bottom:32px}.post-content table th,.post-content table:not(.highlighttable,.highlight table,.gist .highlight) td{min-width:80px;padding:12px 8px;line-height:1.5;border-bottom:1px solid var(--border)}.post-content table th{font-size:14px;text-align:start}.post-content table:not(.highlighttable) td code:only-child{margin:auto 0}.post-content .highlight table{border-radius:var(--radius)}.post-content .highlight:not(table){margin:10px auto;background:var(--hljs-bg)!important;border-radius:var(--radius);direction:ltr}.post-content li>.highlight{margin-inline-end:0}.post-content ul pre{margin-inline-start:calc(var(--gap) * -2)}.post-content .highlight pre{margin:0}.post-content .highlighttable{table-layout:fixed}.post-content .highlighttable td:first-child{width:40px}.post-content .highlighttable td .linenodiv{padding-inline-end:0!important}.post-content .highlighttable td .highlight,.post-content .highlighttable td .linenodiv pre{margin-bottom:0}.post-content code{max-height:40em;margin:auto 4px;padding:4px 6px;font-size:1em;line-height:1.5;background:var(--code-bg);border-radius:2px}.post-content pre code{display:block;margin:auto 0;padding:10px;color:#d5d5d6;background:var(--hljs-bg)!important;border-radius:var(--radius);overflow-x:auto;word-break:break-all}.post-content blockquote{margin:20px 0;padding:0 14px;border-inline-start:3px solid var(--primary)}.post-content hr{margin:30px 0;height:2px;background:var(--tertiary);border:0}.post-content iframe{max-width:100%}.post-content img{border-radius:4px;margin:1rem 0}.post-content img[src*="#center"]{margin:1rem auto}.post-content figure.align-center{text-align:center}.post-content figure>figcaption{color:var(--primary);font-size:16px;font-weight:700;margin:8px 0 16px}.post-content figure>figcaption>p{color:var(--secondary);font-size:14px;font-weight:400}.toc{margin:0 2px 40px;border:1px solid var(--border);background:var(--code-bg);border-radius:var(--radius);padding:.4em}.dark .toc{background:var(--entry)}.toc details summary{cursor:zoom-in;margin-inline-start:20px}.toc details[open] summary{cursor:zoom-out}.toc .details{display:inline;font-weight:500}.toc .inner{margin:0 20px;padding:10px 20px}.toc li ul{margin-inline-start:var(--gap)}.toc summary:focus{outline:0}.post-footer{margin-top:56px}.post-tags li{display:inline-block;margin-inline-end:3px;margin-bottom:5px}.post-tags a,.share-buttons,.paginav{border-radius:var(--radius);background:var(--code-bg);border:1px solid var(--border)}.post-tags a{display:block;padding-inline-start:14px;padding-inline-end:14px;color:var(--secondary);font-size:14px;line-height:34px;background:var(--code-bg)}.post-tags a:hover,.paginav a:hover{background:var(--border)}.share-buttons{margin:14px 0;padding-inline-start:var(--radius);display:flex;justify-content:center;overflow-x:auto}.share-buttons a{margin-top:10px}.share-buttons a:not(:last-of-type){margin-inline-end:12px}h1:hover .anchor,h2:hover .anchor,h3:hover .anchor,h4:hover .anchor,h5:hover .anchor,h6:hover .anchor{display:inline-flex;color:var(--secondary);margin-inline-start:8px;font-weight:500;user-select:none}.paginav{margin:10px 0;display:flex;line-height:30px;border-radius:var(--radius)}.paginav a{padding-inline-start:14px;padding-inline-end:14px;border-radius:var(--radius)}.paginav .title{letter-spacing:1px;text-transform:uppercase;font-size:small;color:var(--secondary)}.paginav .prev,.paginav .next{width:50%}.paginav span:hover:not(.title){box-shadow:0 1px}.paginav .next{margin-inline-start:auto;text-align:right}[dir=rtl] .paginav .next{text-align:left}h1>a>svg{display:inline}img.in-text{display:inline;margin:auto}.buttons,.main .profile{display:flex;justify-content:center}.main .profile{align-items:center;min-height:calc(100vh - var(--header-height) - var(--footer-height) - (var(--gap) * 2));text-align:center}.profile .profile_inner h1{padding:12px 0}.profile img{display:inline-table;border-radius:50%}.buttons{flex-wrap:wrap;max-width:400px;margin:0 auto}.button{background:var(--tertiary);border-radius:var(--radius);margin:8px;padding:6px;transition:transform .1s}.button-inner{padding:0 8px}.button:active{transform:scale(.96)}#searchbox input{padding:4px 10px;width:100%;color:var(--primary);font-weight:700;border:2px solid var(--tertiary);border-radius:var(--radius)}#searchbox input:focus{border-color:var(--secondary)}#searchResults li{list-style:none;border-radius:var(--radius);padding:10px;margin:10px 0;position:relative;font-weight:500}#searchResults{margin:10px 0;width:100%}#searchResults li:active{transition:transform .1s;transform:scale(.98)}#searchResults a{position:absolute;width:100%;height:100%;top:0;left:0;outline:none}#searchResults .focus{transform:scale(.98);border:2px solid var(--tertiary)}.terms-tags li{display:inline-block;margin:10px;font-weight:500}.terms-tags a{display:block;padding:3px 10px;background:var(--tertiary);border-radius:6px;transition:transform .1s}.terms-tags a:active{background:var(--tertiary);transform:scale(.96)}.chroma{background-color:unset!important}::-webkit-scrollbar-track{background:0 0}.list:not(.dark)::-webkit-scrollbar-track{background:var(--code-bg)}::-webkit-scrollbar-thumb{background:var(--tertiary);border:5px solid var(--theme);border-radius:var(--radius)}.list:not(.dark)::-webkit-scrollbar-thumb{border:5px solid var(--code-bg)}::-webkit-scrollbar-thumb:hover{background:var(--secondary)}::-webkit-scrollbar:not(.highlighttable,.highlight table,.gist .highlight){background:var(--theme)}.post-content .highlighttable td .highlight pre code::-webkit-scrollbar{display:none}.post-content :not(table) ::-webkit-scrollbar-thumb{border:2px solid var(--hljs-bg);background:#717175}.post-content :not(table) ::-webkit-scrollbar-thumb:hover{background:#a3a3a5}.gist table::-webkit-scrollbar-thumb{border:2px solid #fff;background:#adadad}.gist table::-webkit-scrollbar-thumb:hover{background:#707070}.post-content table::-webkit-scrollbar-thumb{border-width:2px}@media screen and (min-width:768px){::-webkit-scrollbar{width:19px;height:11px}}@media screen and (max-width:768px){:root{--gap:14px}.profile img{transform:scale(.85)}.first-entry{min-height:260px}.archive-month{flex-direction:column}.archive-year{margin-top:20px}.footer{padding:calc((var(--footer-height) - var(--gap) - 10px)/2)var(--gap)}}@media screen and (max-width:900px){.list .top-link{transform:translateY(-5rem)}}@media(prefers-reduced-motion){.terms-tags a:active,.button:active,.post-entry:active,.top-link,#searchResults .focus,#searchResults li:active{transform:none}}:root{--nav-width:1380px;--article-width:650px;--toc-width:300px}.toc{margin:0 2px 40px;border:1px solid var(--border);background:var(--entry);border-radius:var(--radius);padding:.4em}.toc-container.wide{position:absolute;height:100%;border-right:1px solid var(--border);left:calc((var(--toc-width) + var(--gap)) * -1);top:calc(var(--gap) * 2);width:var(--toc-width)}.wide .toc{position:sticky;top:var(--gap);border:unset;background:unset;border-radius:unset;width:100%;margin:0 2px 40px}.toc details summary{cursor:zoom-in;margin-inline-start:20px;padding:12px 0}.toc details[open] summary{font-weight:500}.toc-container.wide .toc .inner{margin:0}.active{font-size:110%;font-weight:600}.toc ul{list-style-type:circle}.toc .inner{margin:0 0 0 20px;padding:0 15px 15px 20px;font-size:16px;max-height:83vh;overflow-y:auto}.toc .inner::-webkit-scrollbar-thumb{background:var(--border);border:7px solid var(--theme);border-radius:var(--radius)}.toc li ul{margin-inline-start:calc(var(--gap) * .5);list-style-type:none}.toc li{list-style:none;font-size:.95rem;padding-bottom:5px}.toc li a:hover{color:var(--secondary)}.entry-cover{float:right;width:20%;margin-left:20px}.entry-content{margin:20px 0;color:var(--secondary);font-size:20px;line-height:1.6;overflow:hidden;display:block}.terms-tags{text-align:center}.terms-tags a:hover{background:0 0;-moz-transform:scale(1.2);-ms-transform:scale(1.2);-o-transform:scale(1.2);transform:scale(1.3)}.terms-tags a{border-radius:30px;background:0 0;transition:transform .5s}.dark .terms-tags a{background:0 0}.dark .terms-tags a:hover{background:0 0;-moz-transform:scale(1.2);-ms-transform:scale(1.2);-o-transform:scale(1.2);transform:scale(1.3)}.terms-tags li{margin:5px}.bg{color:#e6edf3;background-color:#0d1117}.chroma{color:#e6edf3;background-color:#0d1117}.chroma .x{}.chroma .err{color:#f85149}.chroma .cl{}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{color:#6e7681}.chroma .lnt{white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#737679}.chroma .ln{white-space:pre;-webkit-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#6e7681}.chroma .line{display:flex}.chroma .k{color:#ff7b72}.chroma .kc{color:#79c0ff}.chroma .kd{color:#ff7b72}.chroma .kn{color:#ff7b72}.chroma .kp{color:#79c0ff}.chroma .kr{color:#ff7b72}.chroma .kt{color:#ff7b72}.chroma .n{}.chroma .na{}.chroma .nb{}.chroma .bp{}.chroma .nc{color:#f0883e;font-weight:700}.chroma .no{color:#79c0ff;font-weight:700}.chroma .nd{color:#d2a8ff;font-weight:700}.chroma .ni{color:#ffa657}.chroma .ne{color:#f0883e;font-weight:700}.chroma .nf{color:#d2a8ff;font-weight:700}.chroma .fm{}.chroma .nl{color:#79c0ff;font-weight:700}.chroma .nn{color:#ff7b72}.chroma .nx{}.chroma .py{color:#79c0ff}.chroma .nt{color:#7ee787}.chroma .nv{color:#79c0ff}.chroma .vc{}.chroma .vg{}.chroma .vi{}.chroma .vm{}.chroma .l{color:#a5d6ff}.chroma .ld{color:#79c0ff}.chroma .s{color:#a5d6ff}.chroma .sa{color:#79c0ff}.chroma .sb{color:#a5d6ff}.chroma .sc{color:#a5d6ff}.chroma .dl{color:#79c0ff}.chroma .sd{color:#a5d6ff}.chroma .s2{color:#a5d6ff}.chroma .se{color:#79c0ff}.chroma .sh{color:#79c0ff}.chroma .si{color:#a5d6ff}.chroma .sx{color:#a5d6ff}.chroma .sr{color:#79c0ff}.chroma .s1{color:#a5d6ff}.chroma .ss{color:#a5d6ff}.chroma .m{color:#a5d6ff}.chroma .mb{color:#a5d6ff}.chroma .mf{color:#a5d6ff}.chroma .mh{color:#a5d6ff}.chroma .mi{color:#a5d6ff}.chroma .il{color:#a5d6ff}.chroma .mo{color:#a5d6ff}.chroma .o{color:#ff7b72;font-weight:700}.chroma .ow{color:#ff7b72;font-weight:700}.chroma .p{}.chroma .c{color:#8b949e;font-style:italic}.chroma .ch{color:#8b949e;font-style:italic}.chroma .cm{color:#8b949e;font-style:italic}.chroma .c1{color:#8b949e;font-style:italic}.chroma .cs{color:#8b949e;font-weight:700;font-style:italic}.chroma .cp{color:#8b949e;font-weight:700;font-style:italic}.chroma .cpf{color:#8b949e;font-weight:700;font-style:italic}.chroma .g{}.chroma .gd{color:#ffa198;background-color:#490202}.chroma .ge{font-style:italic}.chroma .gr{color:#ffa198}.chroma .gh{color:#79c0ff;font-weight:700}.chroma .gi{color:#56d364;background-color:#0f5323}.chroma .go{color:#8b949e}.chroma .gp{color:#8b949e}.chroma .gs{font-weight:700}.chroma .gu{color:#79c0ff}.chroma .gt{color:#ff7b72}.chroma .gl{text-decoration:underline}.chroma .w{color:#6e7681} \ No newline at end of file diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 00000000..6c50365b --- /dev/null +++ b/categories/index.html @@ -0,0 +1,4 @@ +Categories | raikiriww's blog
High一下!
\ No newline at end of file diff --git a/categories/index.xml b/categories/index.xml new file mode 100644 index 00000000..08f27ede --- /dev/null +++ b/categories/index.xml @@ -0,0 +1,10 @@ + + + + Categories on raikiriww's blog + https://blog.raikiriww.net/categories/ + Recent content in Categories on raikiriww's blog + Hugo -- gohugo.io + zh + + diff --git a/images/Python_file_write.png b/images/Python_file_write.png new file mode 100644 index 00000000..e129b2b3 Binary files /dev/null and b/images/Python_file_write.png differ diff --git a/images/action-secrets-settings.png b/images/action-secrets-settings.png new file mode 100644 index 00000000..4043c556 Binary files /dev/null and b/images/action-secrets-settings.png differ diff --git a/images/customize-blog.png b/images/customize-blog.png new file mode 100644 index 00000000..83f02075 Binary files /dev/null and b/images/customize-blog.png differ diff --git a/images/hugo-blog-setup.png b/images/hugo-blog-setup.png new file mode 100644 index 00000000..87325e43 Binary files /dev/null and b/images/hugo-blog-setup.png differ diff --git a/images/hugo-github-pages.png b/images/hugo-github-pages.png new file mode 100644 index 00000000..333a30ee Binary files /dev/null and b/images/hugo-github-pages.png differ diff --git a/images/sakana.png b/images/sakana.png new file mode 100644 index 00000000..4bdac3ed Binary files /dev/null and b/images/sakana.png differ diff --git a/images/theme_settings.png b/images/theme_settings.png new file mode 100644 index 00000000..f22d36bc Binary files /dev/null and b/images/theme_settings.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..e9aed370 --- /dev/null +++ b/index.html @@ -0,0 +1,4 @@ +raikiriww's blog
High一下!

Nothing is true,every is permitted

使用 Github Actions 自动部署博客

利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。

...
十月 20, 2023 · 1 分钟 · 213 字 · raikiriww

自定义博客

此篇博客介绍我的博客的修改内容和方法。我的主题为 hugo-PaperMod 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。

...
十月 18, 2023 · 10 分钟 · 1939 字 · raikiriww

搭建博客

使用 Hugo 搭建博客。

...
十月 18, 2023 · 1 分钟 · 57 字 · raikiriww

Python写入文件失败

公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

...
十月 11, 2023 · 1 分钟 · 143 字 · raikiriww
\ No newline at end of file diff --git a/index.xml b/index.xml new file mode 100644 index 00000000..8c7c888d --- /dev/null +++ b/index.xml @@ -0,0 +1,615 @@ + + + + raikiriww's blog + https://blog.raikiriww.net/ + Recent content on raikiriww's blog + Hugo -- gohugo.io + zh + Fri, 20 Oct 2023 21:33:25 +0800 + + 使用 Github Actions 自动部署博客 + https://blog.raikiriww.net/posts/%E4%BD%BF%E7%94%A8-github-actions-%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%8D%9A%E5%AE%A2/ + Fri, 20 Oct 2023 21:33:25 +0800 + + https://blog.raikiriww.net/posts/%E4%BD%BF%E7%94%A8-github-actions-%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%8D%9A%E5%AE%A2/ + <p>利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。</p> + 利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。

+

Github token

+

具体位置为:个人设置界面 -> Developer Settings -> Personal access tokens -> Tokens(classic) 在此界面新生成一个 token,需要勾选 repoworkflow 选项。Expiration 可以设置为 No expiration 。创建完成后会显示你的 token ,它只会显示这一次,你需要将它记下来,后边会用到。

+

workflow 文件

+

想利用 Github Actions ,需要在博客的根目录下创建 .github/workflows/ 文件夹。在该文件夹下创建 yml 文件会被 Github Actions 执行。

+

我的 workflow 文件如下:

+
name: GitHub Pages
+
+on:
+  push:
+    branches:
+      - main  # Set a branch to deploy
+  
+    release:
+      types:
+        - published
+jobs:
+  deploy:
+    runs-on: ubuntu-20.04
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: main
+
+      - name: Setup Hugo
+        uses: peaceiris/actions-hugo@v2
+        with:
+          hugo-version: '0.119.0'
+          # 是否启用 hugo extend
+          # extended: true
+
+      - name: Build
+        run: hugo --minify
+
+      - name: Deploy
+        run: |
+          cd ./public
+          git init
+          git config --global user.name '${{ secrets.GITHUBUSERNAME }}'
+          git config --global user.email '${{ secrets.GITHUBEMAIL }}'
+          git add .
+          git commit -m "${{ github.event.head_commit.message }}"
+          git push --force --quiet "https://${{ secrets.GITHUBUSERNAME }}:${{ secrets.GITHUBTOKEN }}@github.com/${{ secrets.GITHUBUSERNAME }}/${{ secrets.GITHUBUSERNAME }}.github.io.git" master:main
+          #git push --force --quiet "https://${{ secrets.TOKENUSER }}:${{ secrets.CODINGTOKEN }}@e.coding.net/${{ secrets.CODINGUSERNAME }}/${{  secrets.CODINGBLOGREPO }}.git" master:master #coding部署写法,需要的自行取消注释
+          #git push --force --quiet "https://${{ secrets.GITEEUSERNAME }}:${{ secrets.GITEETOKEN }}@gitee.com/${{ secrets.GITEEUSERNAME }}/${{ secrets.GITEEUSERNAME }}.git" master:master #gitee部署写法,需要的自行取消注释          
+

其中,GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN 三个为自定义变量,后边会讲到。

+

源码仓库

+

新建或使用一个老的仓库,可见性设置为 private 。在代码仓库的 Settings 页面找到 Secrets and variables ,点击其中的 Actions ,添加 workflow 中用到的三个变量:GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN

+

action-secrets-settings +

+

上传代码

+

完成上述步骤后即可用 git 提交代码到你的源码仓库,即可在仓库的 Actions 界面看到执行的 workflows。

+

参考

+]]>
+
+ + + 自定义博客 + https://blog.raikiriww.net/posts/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98/ + Wed, 18 Oct 2023 22:29:02 +0800 + + https://blog.raikiriww.net/posts/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98/ + <p>此篇博客介绍我的博客的修改内容和方法。我的主题为 <a href="https://github.com/adityatelange/hugo-PaperMod">hugo-PaperMod</a> 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。</p> + 此篇博客介绍我的博客的修改内容和方法。我的主题为 hugo-PaperMod 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。

+

石蒜小组件

+

来自与 Github 。项目地址为: https://github.com/dsrkafuu/sakana-widget 。具体更改为在 /layouts/partials/extend_head.html 中加入如下代码:

+
<!--  石蒜组件 -->
+<style>
+    html .pull-right{
+        position: absolute;
+        right: 0;
+        top: 70px;
+        
+        transform-origin: 100% 100%; /* 从右下开始变换 */
+    }
+    html #sakana-widget{
+        position: fixed;
+        right: 50px;
+        bottom: 0;
+        
+        transform-origin: 100% 100%; /* 从右下开始变换 */
+}
+</style>
+<link
+rel="stylesheet"
+href="https://cdn.jsdelivr.net/npm/sakana-widget@2.4.1/lib/sakana.min.css"
+/>
+<div id="sakana-widget", style="z-index:999"></div>
+<script>
+function initSakanaWidget() {
+    new SakanaWidget().mount('#sakana-widget');
+}
+</script>
+<script
+async
+onload="initSakanaWidget()"
+src="https://cdn.jsdelivr.net/npm/sakana-widget@2.4.1/lib/sakana.min.js"
+></script>
+

重新编译后即可拥有可爱石蒜小组件。sakana +

+

High 一下

+

有两种 High 一下的代码实现:

+ +
javascript:(function(){function c(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",f);e.setAttribute("class",l);document.body.appendChild(e)}function h(){var e=document.getElementsByClassName(l);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function p(){var e=document.createElement("div");e.setAttribute("class",a);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function d(e){return{height:e.offsetHeight,width:e.offsetWidth}}function v(i){var s=d(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function m(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function g(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function y(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function E(e){var t=m(e);return t>=w&&t<=b+w}function S(){var e=document.createElement("audio");e.setAttribute("class",l);e.src=i;e.loop=false;e.addEventListener("canplay",function(){setTimeout(function(){x(k)},500);setTimeout(function(){N();p();for(var e=0;e<O.length;e++){T(O[e])}},15500)},true);e.addEventListener("ended",function(){N();h()},true);e.innerHTML=" <p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p> <p>";document.body.appendChild(e);e.play()}function x(e){e.className+=" "+s+" "+o}function T(e){e.className+=" "+s+" "+u[Math.floor(Math.random()*u.length)]}function N(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.mp3";var s="mw-harlem_shake_me";var o="im_first";var u=["im_drunk","im_baked","im_trippin","im_blown"];var a="mw-strobe_light";var f="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var l="mw_added_css";var b=g();var w=y();var C=document.getElementsByTagName("*");var k=null;for(var L=0;L<C.length;L++){var A=C[L];if(v(A)){if(E(A)){k=A;break}}}if(A===null){console.warn("Could not find a node of the right size. Please try a different page.");return}c();S();var O=[];for(var L=0;L<C.length;L++){var A=C[L];if(v(A)){O.push(A)}}})()
+
    +
  • 第二种:来自于 Github 的 代码 :
  • +
+
javascript:(function(){function h(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",l);e.setAttribute("class",c);document.body.appendChild(e)}function p(){var e=document.getElementsByClassName(c);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function d(){var e=document.createElement("div");e.setAttribute("class",f);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function v(e){return{height:e.offsetHeight,width:e.offsetWidth}}function m(i){var s=v(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function g(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function y(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function b(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function S(e){var t=g(e);return t>=E&&t<=w+E}function x(){var e=document.createElement("audio");e.setAttribute("class",c);e.src=i;e.loop=false;var t=false,n=false,r=false;e.addEventListener("timeupdate",function(){var i=e.currentTime,s=D,o=s.length,u;if(i>=.5&&!t){t=true;T(_)}if(i>=15.5&&!n){n=true;k();d();for(u=0;u<o;u++){N(s[u])}}if(e.currentTime>=28.4&&!r){r=true;C()}},true);e.addEventListener("ended",function(){k();p()},true);e.innerHTML="<p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p>";document.body.appendChild(e);e.play()}function T(e){e.className+=" "+s+" "+u}function N(e){e.className+=" "+s+" "+a[Math.floor(Math.random()*a.length)]}function C(){var e=document.getElementsByClassName(s);for(var t=0;t<e.length;){e[t].className=e[t].className.replace(s,o)}s=o}function k(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.ogg";var s="mw-harlem_shake_me";var o="mw-harlem_shake_slow";var u="im_first";var a=["im_drunk","im_baked","im_trippin","im_blown"];var f="mw-strobe_light";var l="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var c="mw_added_css";var w=y();var E=b();var L=document.getElementsByTagName("*"),A=L.length,O,M;var _=null;for(O=0;O<A;O++){M=L[O];if(m(M)){if(S(M)){_=M;break}}}if(M===null){console.warn("Could not find a node of the right size. Please try a different page.");return}h();x();var D=[];for(O=0;O<A;O++){M=L[O];if(m(M)){D.push(M)}}})()
+

以上两种差不多,我个人用的是第二种。具体用法为在 /layouts/partials/extend_head.html 中加入如下代码:

+
<!--  High 一下 --> 
+<div class="pull-right", style="z-index:999">
+<a title="把这个链接拖到你的Chrome收藏夹工具栏中" href='javascript:(function(){function h(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",l);e.setAttribute("class",c);document.body.appendChild(e)}function p(){var e=document.getElementsByClassName(c);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function d(){var e=document.createElement("div");e.setAttribute("class",f);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function v(e){return{height:e.offsetHeight,width:e.offsetWidth}}function m(i){var s=v(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function g(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function y(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function b(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function S(e){var t=g(e);return t>=E&&t<=w+E}function x(){var e=document.createElement("audio");e.setAttribute("class",c);e.src=i;e.loop=false;var t=false,n=false,r=false;e.addEventListener("timeupdate",function(){var i=e.currentTime,s=D,o=s.length,u;if(i>=.5&&!t){t=true;T(_)}if(i>=15.5&&!n){n=true;k();d();for(u=0;u<o;u++){N(s[u])}}if(e.currentTime>=28.4&&!r){r=true;C()}},true);e.addEventListener("ended",function(){k();p()},true);e.innerHTML="<p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p>";document.body.appendChild(e);e.play()}function T(e){e.className+=" "+s+" "+u}function N(e){e.className+=" "+s+" "+a[Math.floor(Math.random()*a.length)]}function C(){var e=document.getElementsByClassName(s);for(var t=0;t<e.length;){e[t].className=e[t].className.replace(s,o)}s=o}function k(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.ogg";var s="mw-harlem_shake_me";var o="mw-harlem_shake_slow";var u="im_first";var a=["im_drunk","im_baked","im_trippin","im_blown"];var f="mw-strobe_light";var l="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var c="mw_added_css";var w=y();var E=b();var L=document.getElementsByTagName("*"),A=L.length,O,M;var _=null;for(O=0;O<A;O++){M=L[O];if(m(M)){if(S(M)){_=M;break}}}if(M===null){console.warn("Could not find a node of the right size. Please try a different page.");return}h();x();var D=[];for(O=0;O<A;O++){M=L[O];if(m(M)){D.push(M)}}})()'>High一下!</a>
+</div>
+

其中的 href= 的内容替换为上述两种的其中一种即可。

+

修改目录位置到文章页左边

+

根据 sulvblog 的方法来改。

+

修改 toc.html

+

先修改 layouts/partials/toc.html 的代码,替换为:

+
{{- $headers := findRE "<h[1-6].*?>(.|\n])+?</h[1-6]>" .Content -}}
+{{- $has_headers := ge (len $headers) 1 -}}
+{{- if $has_headers -}}
+<aside id="toc-container" class="toc-container wide">
+    <div class="toc">
+        <details {{if (.Param "TocOpen") }} open{{ end }}>
+            <summary accesskey="c" title="(Alt + C)">
+                <span class="details">{{- i18n "toc" | default "Table of Contents" }}</span>
+            </summary>
+
+            <div class="inner">
+                {{- $largest := 6 -}}
+                {{- range $headers -}}
+                {{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
+                {{- $headerLevel := len (seq $headerLevel) -}}
+                {{- if lt $headerLevel $largest -}}
+                {{- $largest = $headerLevel -}}
+                {{- end -}}
+                {{- end -}}
+
+                {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}}
+
+                {{- $.Scratch.Set "bareul" slice -}}
+                <ul>
+                    {{- range seq (sub $firstHeaderLevel $largest) -}}
+                    <ul>
+                        {{- $.Scratch.Add "bareul" (sub (add $largest .) 1) -}}
+                        {{- end -}}
+                        {{- range $i, $header := $headers -}}
+                        {{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
+                        {{- $headerLevel := len (seq $headerLevel) -}}
+
+                        {{/* get id="xyz" */}}
+                        {{- $id := index (findRE "(id=\"(.*?)\")" $header 9) 0 }}
+
+                        {{- /* strip id="" to leave xyz, no way to get regex capturing groups in hugo */ -}}
+                        {{- $cleanedID := replace (replace $id "id=\"" "") "\"" "" }}
+                        {{- $header := replaceRE "<h[1-6].*?>((.|\n])+?)</h[1-6]>" "$1" $header -}}
+
+                        {{- if ne $i 0 -}}
+                        {{- $prevHeaderLevel := index (findRE "[1-6]" (index $headers (sub $i 1)) 1) 0 -}}
+                        {{- $prevHeaderLevel := len (seq $prevHeaderLevel) -}}
+                        {{- if gt $headerLevel $prevHeaderLevel -}}
+                        {{- range seq $prevHeaderLevel (sub $headerLevel 1) -}}
+                        <ul>
+                            {{/* the first should not be recorded */}}
+                            {{- if ne $prevHeaderLevel . -}}
+                            {{- $.Scratch.Add "bareul" . -}}
+                            {{- end -}}
+                            {{- end -}}
+                            {{- else -}}
+                            </li>
+                            {{- if lt $headerLevel $prevHeaderLevel -}}
+                            {{- range seq (sub $prevHeaderLevel 1) -1 $headerLevel -}}
+                            {{- if in ($.Scratch.Get "bareul") . -}}
+                        </ul>
+                        {{/* manually do pop item */}}
+                        {{- $tmp := $.Scratch.Get "bareul" -}}
+                        {{- $.Scratch.Delete "bareul" -}}
+                        {{- $.Scratch.Set "bareul" slice}}
+                        {{- range seq (sub (len $tmp) 1) -}}
+                        {{- $.Scratch.Add "bareul" (index $tmp (sub . 1)) -}}
+                        {{- end -}}
+                        {{- else -}}
+                    </ul>
+                    </li>
+                    {{- end -}}
+                    {{- end -}}
+                    {{- end -}}
+                    {{- end }}
+                    <li>
+                        <a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
+                        {{- else }}
+                    <li>
+                        <a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
+                        {{- end -}}
+                        {{- end -}}
+                        <!-- {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}} -->
+                        {{- $firstHeaderLevel := $largest }}
+                        {{- $lastHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers (sub (len $headers) 1)) 1) 0)) }}
+                    </li>
+                    {{- range seq (sub $lastHeaderLevel $firstHeaderLevel) -}}
+                    {{- if in ($.Scratch.Get "bareul") (add . $firstHeaderLevel) }}
+                </ul>
+                {{- else }}
+                </ul>
+                </li>
+                {{- end -}}
+                {{- end }}
+                </ul>
+            </div>
+        </details>
+    </div>
+</aside>
+<script>
+    let activeElement;
+    let elements;
+    window.addEventListener('DOMContentLoaded', function (event) {
+        checkTocPosition();
+
+        elements = document.querySelectorAll('h1[id],h2[id],h3[id],h4[id],h5[id],h6[id]');
+         // Make the first header active
+         activeElement = elements[0];
+         const id = encodeURI(activeElement.getAttribute('id')).toLowerCase();
+         document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
+     }, false);
+
+    window.addEventListener('resize', function(event) {
+        checkTocPosition();
+    }, false);
+
+    window.addEventListener('scroll', () => {
+        // Check if there is an object in the top half of the screen or keep the last item active
+        activeElement = Array.from(elements).find((element) => {
+            if ((getOffsetTop(element) - window.pageYOffset) > 0 && 
+                (getOffsetTop(element) - window.pageYOffset) < window.innerHeight/2) {
+                return element;
+            }
+        }) || activeElement
+
+        elements.forEach(element => {
+             const id = encodeURI(element.getAttribute('id')).toLowerCase();
+             if (element === activeElement){
+                 document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
+             } else {
+                 document.querySelector(`.inner ul li a[href="#${id}"]`).classList.remove('active');
+             }
+         })
+     }, false);
+
+    const main = parseInt(getComputedStyle(document.body).getPropertyValue('--article-width'), 10);
+    const toc = parseInt(getComputedStyle(document.body).getPropertyValue('--toc-width'), 10);
+    const gap = parseInt(getComputedStyle(document.body).getPropertyValue('--gap'), 10);
+
+    function checkTocPosition() {
+        const width = document.body.scrollWidth;
+
+        if (width - main - (toc * 2) - (gap * 4) > 0) {
+            document.getElementById("toc-container").classList.add("wide");
+        } else {
+            document.getElementById("toc-container").classList.remove("wide");
+        }
+    }
+
+    function getOffsetTop(element) {
+        if (!element.getClientRects().length) {
+            return 0;
+        }
+        let rect = element.getBoundingClientRect();
+        let win = element.ownerDocument.defaultView;
+        return rect.top + win.pageYOffset;   
+    }
+</script>
+{{- end }}
+

调用

+

layouts/_default/single.html 文件中默认有 toc.html 的调用,如果未更改的话不用管,更改的话请调用:

+
{{- if (.Param "ShowToc") }}
+{{- partial "toc.html" . }}
+{{- end }}
+

修改 css

+

修改 css/extended/blank.css 文件,加入下方代码:

+
:root {
+    --nav-width: 1380px;
+    --article-width: 650px;
+    --toc-width: 300px;
+}
+
+.toc {
+    margin: 0 2px 40px 2px;
+    border: 1px solid var(--border);
+    background: var(--entry);
+    border-radius: var(--radius);
+    padding: 0.4em;
+}
+
+.toc-container.wide {
+    position: absolute;
+    height: 100%;
+    border-right: 1px solid var(--border);
+    left: calc((var(--toc-width) + var(--gap)) * -1);
+    top: calc(var(--gap) * 2);
+    width: var(--toc-width);
+}
+
+.wide .toc {
+    position: sticky;
+    top: var(--gap);
+    border: unset;
+    background: unset;
+    border-radius: unset;
+    width: 100%;
+    margin: 0 2px 40px 2px;
+}
+
+.toc details summary {
+    cursor: zoom-in;
+    margin-inline-start: 20px;
+    padding: 12px 0;
+}
+
+.toc details[open] summary {
+    font-weight: 500;
+}
+
+.toc-container.wide .toc .inner {
+    margin: 0;
+}
+
+.active {
+    font-size: 110%;
+    font-weight: 600;
+}
+
+.toc ul {
+    list-style-type: circle;
+}
+
+.toc .inner {
+    margin: 0 0 0 20px;
+    padding: 0px 15px 15px 20px;
+    font-size: 16px;
+
+    /*目录显示高度*/
+    max-height: 83vh;
+    overflow-y: auto;
+}
+
+.toc .inner::-webkit-scrollbar-thumb {  /*滚动条*/
+    background: var(--border);
+    border: 7px solid var(--theme);
+    border-radius: var(--radius);
+}
+
+.toc li ul {
+    margin-inline-start: calc(var(--gap) * 0.5);
+    list-style-type: none;
+}
+
+.toc li {
+    list-style: none;
+    font-size: 0.95rem;
+    padding-bottom: 5px;
+}
+
+.toc li a:hover {
+    color: var(--secondary);
+}
+

重新编译后即可看到目录到了左边。

+

修改主题内容宽度

+

修改 ·assets\css\core\theme-vars.css 文件的 :root 节点中的 --main-width 我设置的是 1024px

+

修改代码块

+

修改渲染方式

+

放弃主题默认的 Highlight.js,改为 Hugo 默认的 chroma 方式渲染。根据 官方说明 来改。我用的 style 为 github-dark

+

设置代码块最大高度

+

assets\css\common\post-single.css 文件中找到 .post-content code 增加 max-height: 40em; 。目前设置好最大高度后会与 lineNos: true 设置冲突,会显示两个滑动条 :( ,所以就先不开它。

+

修改文章列表显示的图片位置

+

默认显示的图片在摘要上方而且很大,一页只能显示几个,感觉体验不是很好,所以将它改为在摘要右方显示。我很喜欢 CoolShell 的文章页的显示方法,准备改成差不多样子的。

+

修改 list.html

+

文件为 layouts\_default\list.html 。默认的图片显示代码为:

+
{{- $isHidden := (site.Params.cover.hidden | default site.Params.cover.hiddenInList) }}
+{{- partial "cover.html" (dict "cxt" . "IsHome" true "isHidden" $isHidden) }}
+

位于 <header class="entry-header"> 的上方。将其移动到 <div class="entry-content"> 中并替换默认的 Summary 处理方式,如下所示:

+
<div class="entry-content">
+    {{- $isHidden := (site.Params.cover.hidden | default site.Params.cover.hiddenInList) }}
+    {{- partial "cover.html" (dict "cxt" . "IsHome" true "isHidden" $isHidden) }}
+    {{ .Summary | replaceRE "\n" "<br>" | safeHTML }}{{ if .Truncated }}...{{ end }}
+</div>
+

修改 cover.html

+

文件为 layouts\partials\cover.html 。将 所有 <img 块都加上 align="right" 。完整如下所示:

+
{{- with .cxt}} {{/* Apply proper context from dict */}}
+{{- if (and .Params.cover.image (not $.isHidden)) }}
+{{- $alt := (.Params.cover.alt | default .Params.cover.caption | plainify) }}
+<figure class="entry-cover">
+    {{- $responsiveImages := (.Params.cover.responsiveImages | default site.Params.cover.responsiveImages) | default true }}
+    {{- $addLink := (and site.Params.cover.linkFullImages (not $.IsHome)) }}
+    {{- $pageBundleCover     := (.Resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
+    {{- $globalResourcesCover := (resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
+    {{- $cover := (or $pageBundleCover $globalResourcesCover)}}
+    {{- if $cover -}}{{/* i.e it is present in page bundle */}}
+        {{- if $addLink }}<a href="{{ (path.Join .RelPermalink .Params.cover.image) | absURL }}" target="_blank"
+            rel="noopener noreferrer">{{ end -}}
+        {{- $sizes := (slice "360" "480" "720" "1080" "1500") }}
+        {{- $processableFormats := (slice "jpg" "jpeg" "png" "tif" "bmp" "gif") -}}
+        {{- if hugo.IsExtended -}}
+            {{- $processableFormats = $processableFormats | append "webp" -}}
+        {{- end -}}
+        {{- $prod := (hugo.IsProduction | or (eq site.Params.env "production")) }}
+        {{- if (and (in $processableFormats $cover.MediaType.SubType) ($responsiveImages) (eq $prod true)) }}
+        <img loading="lazy" align="right" srcset="{{- range $size := $sizes -}}
+                        {{- if (ge $cover.Width $size) -}}
+                        {{ printf "%s %s" (($cover.Resize (printf "%sx" $size)).Permalink) (printf "%sw ," $size) -}}
+                        {{ end }}
+                    {{- end -}}{{$cover.Permalink }} {{printf "%dw" ($cover.Width)}}" 
+            sizes="(min-width: 768px) 720px, 100vw" src="{{ $cover.Permalink }}" alt="{{ $alt }}" 
+            width="{{ $cover.Width }}" height="{{ $cover.Height }}">
+        {{- else }}{{/* Unprocessable image or responsive images disabled */}}
+        <img loading="lazy" align="right" src="{{ (path.Join .RelPermalink .Params.cover.image) | absURL }}" alt="{{ $alt }}">
+        {{- end }}
+    {{- else }}{{/* For absolute urls and external links, no img processing here */}}
+        {{- if $addLink }}<a href="{{ (.Params.cover.image) | absURL }}" target="_blank"
+            rel="noopener noreferrer">{{ end -}}
+            <img loading="lazy" align="right" src="{{ (.Params.cover.image) | absURL }}" alt="{{ $alt }}">
+    {{- end }}
+    {{- if $addLink }}</a>{{ end -}}
+    {{/*  Display Caption  */}}
+    {{- if not $.IsHome }}
+        {{ with .Params.cover.caption }}<p>{{ . | markdownify }}</p>{{- end }}
+    {{- end }}
+</figure>
+{{- end }}{{/* End image */}}
+{{- end -}}{{/* End context */ -}}
+

增加 css

+

在文件 assets\css\extended\blank.css 中增加以下代码:

+
.entry-cover {
+    float:right;
+    width: 20%;
+    margin-left: 20px;
+}
+
+.entry-content {
+    margin: 20px 0;
+    color: var(--secondary);
+    font-size: 14px;
+    line-height: 1.6;
+    overflow: hidden;
+    display: block;
+}
+

这样做完的效果就是文章列表页的摘要可以自由显示文字和图片,默认的 cover 在文字右边,文字会环绕图片显示。

+

标签页词云效果

+

根据 Sulv’s Blog 的方法来改。

+

修改 terms.html

+

layouts/_default/terms.html 中的 <ul class="terms-tags"> 代码块替换为:

+
<ul class="terms-tags">
+    {{- $type := .Type }}
+    {{- range $key, $value := .Data.Terms.Alphabetical }}
+    {{- $name := .Name }}
+    {{- $count := .Count }}
+    {{- with $.Site.GetPage (printf "/%s/%s" $type $name) }}
+    <li>
+        {{ $largestFontSize := 1.5 }}
+        {{ $smallestFontSize := 1 }}
+        {{ $fontSpread := sub $largestFontSize $smallestFontSize }}
+        {{ $max := add (len (index $.Site.Taxonomies.tags.ByCount 0).Pages) 1 }}
+        {{ $min := len (index $.Site.Taxonomies.tags.ByCount.Reverse 0).Pages }}
+        {{ $spread := sub $max $min }}
+        {{ $fontStep := div $fontSpread $spread }}
+        {{ $weigth := div (sub (math.Log $count) (math.Log $min)) (sub (math.Log $max) (math.Log $min)) }}
+        {{ $currentFontSize := (add $smallestFontSize (mul (sub $largestFontSize $smallestFontSize) $weigth)) }}
+        <a href="{{ .Permalink }}" style="font-size: {{ $currentFontSize }}rem; font-weight: {{ mul $currentFontSize 200 }};">
+            {{ .Name }} <sup><strong><sup>{{ $count }}</sup></strong></sup>
+        </a>
+    </li>
+    {{- end }}
+    {{- end }}
+</ul>
+

增加 css

+

assets/css/extended/blank.css 中增加如下代码:

+
/*标签*/
+.terms-tags {
+    text-align: center;
+}
+
+.terms-tags a:hover {
+    background: none;
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.3);
+}
+
+.terms-tags a {
+    border-radius: 30px;
+    background: none;
+    transition: transform 0.5s;
+}
+
+.dark .terms-tags a {
+    background: none;
+}
+
+.dark .terms-tags a:hover {
+    background: none;
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.3);
+}
+
+.terms-tags li {
+    margin: 5px;
+}
+
]]>
+
+ + + 搭建博客 + https://blog.raikiriww.net/posts/%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2/ + Wed, 18 Oct 2023 22:20:34 +0800 + + https://blog.raikiriww.net/posts/%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2/ + <p>使用 Hugo 搭建博客。</p> + 使用 Hugo 搭建博客。

+

安装 Hugo

+

根据 Hugo 官网 的文档来安装 Hugo。

+

安装主题

+

我使用的主题为:hugo-PaperMod ,根据主题文档安装主题(推荐使用 submodule 的方式安装)。将默认的配置文件 hugo.toml 的后缀改为 yaml,方便使用。

+

主题配置

+

复制主题网站给的 Sample config.yml 的内容到 hugo.yaml 中,额外增加:

+
languageCode: zh
+defaultContentLanguage: zh
+

将网站语言设置为中文。

+

默认文章配置

+

复制 Sample Page.md 的内容到 archetypes/default.md 中(title 和 date 不覆盖,只将 toml 格式的配置改为 yaml 格式即可)。可以省去自己一个一个寻找增加的时间,当然,具体内容还是要根据自己的要求来改。

+

写文章

+

使用命令 hugo new content posts/my-first-post.md 来新建一篇文章。

+

本地预览

+

使用命令 hugo server -D 预览生成好的网页。

]]>
+
+ + + Python写入文件失败 + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + Wed, 11 Oct 2023 10:29:09 +0800 + + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + <p>公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。</p> + 公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

+

查找问题

+

大概的代码示例如下:

+
# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

从代码结构来看确实没什么问题,是先保存数据再降低电压,即使后边的操作导致死机也是在写入操作完成后,应该不会影响保存的数据才对。但事实是确实有影响,在 windows 上测试了好几次保存的数据都为空。with open() 语句是 Python 中常用的文件操作语句,不应该会导致写入异常,于是怀疑是降压操作导致的。

+

分析问题

+

在 Python 中,当使用 with open() 语句来写入文件时,它会负责管理文件的打开和关闭,通常情况下, with 语句块结束后,Python 会自动关闭文件,并确保所有数据写入硬盘。但,这个操作不是立即发生的。

+

当写入文件时,操作系统通常会缓存这些操作,以便一次性的将多个写入操作合并,从而提高效率。这意味着即使 Python 代码执行了写入操作(也就是 write()),也不能保证这些数据已经永久的保存到了硬盘上。如果在 with 语句块结束后立即死机,这些数据可能会丢失。

+

解决方法

+

现在知道了导致数据保存失败的原因是出在 windows 的系统缓存机制上,那只要找到方法可以强制系统将缓存的数据写入硬盘就好了。修改后的代码如下:

+
# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+  
+    # 确保数据从 Python 的内部缓冲区写入操作系统的缓冲区
+    f.flush()
+  
+    # 确保数据从操作系统的缓冲区写入磁盘
+    os.fsync(f.fileno())
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

新增了两行代码。

+
    +
  • f.flush() 的作用为刷新 Python 的内部缓冲区,确保所有数据写入操作系统的缓冲区。但这个并不能保证操作系统会立刻将数据写入硬盘。
  • +
  • os.fsync(f.fileno()) 的作用为强制操作系统将其缓冲区的数据写入硬盘。这样就保证了如果之后的代码导致系统死机,这部分数据也会完整的保存在硬盘上。
  • +
+

将修改后的程序在 windows 上测试,数据每次都会完整的保存在硬盘上。

+

后记

+

在 Microsoft 的一篇官方文档中有提到 disk write caching ,也就是写入缓存,并给出了关闭的方法。

+

关于 disk write caching ,官方的描述为:

+
+

Additionally, turning disk write caching on may increase operating system performance; however, it may also result in the loss of information if a power failure, equipment failure, or software failure occurs.

+
+

确实与我遇到的情况一样。

+

还有一篇更详细一点的介绍:https://learn.microsoft.com/en-US/windows/client-management/client-tools/change-default-removal-policy-external-storage-media

+

总的来说 disk write caching 在一般情况下可以提高性能。但在需要确保极端情况下写入数据完整性时,可以考虑关闭或者手动强制写入。

]]>
+
+ +
+
diff --git a/page/1/index.html b/page/1/index.html new file mode 100644 index 00000000..7af759cb --- /dev/null +++ b/page/1/index.html @@ -0,0 +1 @@ +https://blog.raikiriww.net/ \ No newline at end of file diff --git a/posts/index.html b/posts/index.html new file mode 100644 index 00000000..eb91cb1a --- /dev/null +++ b/posts/index.html @@ -0,0 +1,5 @@ +Posts | raikiriww's blog
High一下!

使用 Github Actions 自动部署博客

利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。

...
十月 20, 2023 · 1 分钟 · 213 字 · raikiriww

自定义博客

此篇博客介绍我的博客的修改内容和方法。我的主题为 hugo-PaperMod 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。

...
十月 18, 2023 · 10 分钟 · 1939 字 · raikiriww

搭建博客

使用 Hugo 搭建博客。

...
十月 18, 2023 · 1 分钟 · 57 字 · raikiriww

Python写入文件失败

公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

...
十月 11, 2023 · 1 分钟 · 143 字 · raikiriww
\ No newline at end of file diff --git a/posts/index.xml b/posts/index.xml new file mode 100644 index 00000000..e166d1b4 --- /dev/null +++ b/posts/index.xml @@ -0,0 +1,615 @@ + + + + Posts on raikiriww's blog + https://blog.raikiriww.net/posts/ + Recent content in Posts on raikiriww's blog + Hugo -- gohugo.io + zh + Fri, 20 Oct 2023 21:33:25 +0800 + + 使用 Github Actions 自动部署博客 + https://blog.raikiriww.net/posts/%E4%BD%BF%E7%94%A8-github-actions-%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%8D%9A%E5%AE%A2/ + Fri, 20 Oct 2023 21:33:25 +0800 + + https://blog.raikiriww.net/posts/%E4%BD%BF%E7%94%A8-github-actions-%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%8D%9A%E5%AE%A2/ + <p>利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。</p> + 利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。

+

Github token

+

具体位置为:个人设置界面 -> Developer Settings -> Personal access tokens -> Tokens(classic) 在此界面新生成一个 token,需要勾选 repoworkflow 选项。Expiration 可以设置为 No expiration 。创建完成后会显示你的 token ,它只会显示这一次,你需要将它记下来,后边会用到。

+

workflow 文件

+

想利用 Github Actions ,需要在博客的根目录下创建 .github/workflows/ 文件夹。在该文件夹下创建 yml 文件会被 Github Actions 执行。

+

我的 workflow 文件如下:

+
name: GitHub Pages
+
+on:
+  push:
+    branches:
+      - main  # Set a branch to deploy
+  
+    release:
+      types:
+        - published
+jobs:
+  deploy:
+    runs-on: ubuntu-20.04
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: main
+
+      - name: Setup Hugo
+        uses: peaceiris/actions-hugo@v2
+        with:
+          hugo-version: '0.119.0'
+          # 是否启用 hugo extend
+          # extended: true
+
+      - name: Build
+        run: hugo --minify
+
+      - name: Deploy
+        run: |
+          cd ./public
+          git init
+          git config --global user.name '${{ secrets.GITHUBUSERNAME }}'
+          git config --global user.email '${{ secrets.GITHUBEMAIL }}'
+          git add .
+          git commit -m "${{ github.event.head_commit.message }}"
+          git push --force --quiet "https://${{ secrets.GITHUBUSERNAME }}:${{ secrets.GITHUBTOKEN }}@github.com/${{ secrets.GITHUBUSERNAME }}/${{ secrets.GITHUBUSERNAME }}.github.io.git" master:main
+          #git push --force --quiet "https://${{ secrets.TOKENUSER }}:${{ secrets.CODINGTOKEN }}@e.coding.net/${{ secrets.CODINGUSERNAME }}/${{  secrets.CODINGBLOGREPO }}.git" master:master #coding部署写法,需要的自行取消注释
+          #git push --force --quiet "https://${{ secrets.GITEEUSERNAME }}:${{ secrets.GITEETOKEN }}@gitee.com/${{ secrets.GITEEUSERNAME }}/${{ secrets.GITEEUSERNAME }}.git" master:master #gitee部署写法,需要的自行取消注释          
+

其中,GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN 三个为自定义变量,后边会讲到。

+

源码仓库

+

新建或使用一个老的仓库,可见性设置为 private 。在代码仓库的 Settings 页面找到 Secrets and variables ,点击其中的 Actions ,添加 workflow 中用到的三个变量:GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN

+

action-secrets-settings +

+

上传代码

+

完成上述步骤后即可用 git 提交代码到你的源码仓库,即可在仓库的 Actions 界面看到执行的 workflows。

+

参考

+]]>
+
+ + + 自定义博客 + https://blog.raikiriww.net/posts/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98/ + Wed, 18 Oct 2023 22:29:02 +0800 + + https://blog.raikiriww.net/posts/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98/ + <p>此篇博客介绍我的博客的修改内容和方法。我的主题为 <a href="https://github.com/adityatelange/hugo-PaperMod">hugo-PaperMod</a> 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。</p> + 此篇博客介绍我的博客的修改内容和方法。我的主题为 hugo-PaperMod 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。

+

石蒜小组件

+

来自与 Github 。项目地址为: https://github.com/dsrkafuu/sakana-widget 。具体更改为在 /layouts/partials/extend_head.html 中加入如下代码:

+
<!--  石蒜组件 -->
+<style>
+    html .pull-right{
+        position: absolute;
+        right: 0;
+        top: 70px;
+        
+        transform-origin: 100% 100%; /* 从右下开始变换 */
+    }
+    html #sakana-widget{
+        position: fixed;
+        right: 50px;
+        bottom: 0;
+        
+        transform-origin: 100% 100%; /* 从右下开始变换 */
+}
+</style>
+<link
+rel="stylesheet"
+href="https://cdn.jsdelivr.net/npm/sakana-widget@2.4.1/lib/sakana.min.css"
+/>
+<div id="sakana-widget", style="z-index:999"></div>
+<script>
+function initSakanaWidget() {
+    new SakanaWidget().mount('#sakana-widget');
+}
+</script>
+<script
+async
+onload="initSakanaWidget()"
+src="https://cdn.jsdelivr.net/npm/sakana-widget@2.4.1/lib/sakana.min.js"
+></script>
+

重新编译后即可拥有可爱石蒜小组件。sakana +

+

High 一下

+

有两种 High 一下的代码实现:

+ +
javascript:(function(){function c(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",f);e.setAttribute("class",l);document.body.appendChild(e)}function h(){var e=document.getElementsByClassName(l);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function p(){var e=document.createElement("div");e.setAttribute("class",a);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function d(e){return{height:e.offsetHeight,width:e.offsetWidth}}function v(i){var s=d(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function m(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function g(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function y(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function E(e){var t=m(e);return t>=w&&t<=b+w}function S(){var e=document.createElement("audio");e.setAttribute("class",l);e.src=i;e.loop=false;e.addEventListener("canplay",function(){setTimeout(function(){x(k)},500);setTimeout(function(){N();p();for(var e=0;e<O.length;e++){T(O[e])}},15500)},true);e.addEventListener("ended",function(){N();h()},true);e.innerHTML=" <p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p> <p>";document.body.appendChild(e);e.play()}function x(e){e.className+=" "+s+" "+o}function T(e){e.className+=" "+s+" "+u[Math.floor(Math.random()*u.length)]}function N(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.mp3";var s="mw-harlem_shake_me";var o="im_first";var u=["im_drunk","im_baked","im_trippin","im_blown"];var a="mw-strobe_light";var f="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var l="mw_added_css";var b=g();var w=y();var C=document.getElementsByTagName("*");var k=null;for(var L=0;L<C.length;L++){var A=C[L];if(v(A)){if(E(A)){k=A;break}}}if(A===null){console.warn("Could not find a node of the right size. Please try a different page.");return}c();S();var O=[];for(var L=0;L<C.length;L++){var A=C[L];if(v(A)){O.push(A)}}})()
+
    +
  • 第二种:来自于 Github 的 代码 :
  • +
+
javascript:(function(){function h(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",l);e.setAttribute("class",c);document.body.appendChild(e)}function p(){var e=document.getElementsByClassName(c);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function d(){var e=document.createElement("div");e.setAttribute("class",f);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function v(e){return{height:e.offsetHeight,width:e.offsetWidth}}function m(i){var s=v(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function g(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function y(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function b(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function S(e){var t=g(e);return t>=E&&t<=w+E}function x(){var e=document.createElement("audio");e.setAttribute("class",c);e.src=i;e.loop=false;var t=false,n=false,r=false;e.addEventListener("timeupdate",function(){var i=e.currentTime,s=D,o=s.length,u;if(i>=.5&&!t){t=true;T(_)}if(i>=15.5&&!n){n=true;k();d();for(u=0;u<o;u++){N(s[u])}}if(e.currentTime>=28.4&&!r){r=true;C()}},true);e.addEventListener("ended",function(){k();p()},true);e.innerHTML="<p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p>";document.body.appendChild(e);e.play()}function T(e){e.className+=" "+s+" "+u}function N(e){e.className+=" "+s+" "+a[Math.floor(Math.random()*a.length)]}function C(){var e=document.getElementsByClassName(s);for(var t=0;t<e.length;){e[t].className=e[t].className.replace(s,o)}s=o}function k(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.ogg";var s="mw-harlem_shake_me";var o="mw-harlem_shake_slow";var u="im_first";var a=["im_drunk","im_baked","im_trippin","im_blown"];var f="mw-strobe_light";var l="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var c="mw_added_css";var w=y();var E=b();var L=document.getElementsByTagName("*"),A=L.length,O,M;var _=null;for(O=0;O<A;O++){M=L[O];if(m(M)){if(S(M)){_=M;break}}}if(M===null){console.warn("Could not find a node of the right size. Please try a different page.");return}h();x();var D=[];for(O=0;O<A;O++){M=L[O];if(m(M)){D.push(M)}}})()
+

以上两种差不多,我个人用的是第二种。具体用法为在 /layouts/partials/extend_head.html 中加入如下代码:

+
<!--  High 一下 --> 
+<div class="pull-right", style="z-index:999">
+<a title="把这个链接拖到你的Chrome收藏夹工具栏中" href='javascript:(function(){function h(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",l);e.setAttribute("class",c);document.body.appendChild(e)}function p(){var e=document.getElementsByClassName(c);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function d(){var e=document.createElement("div");e.setAttribute("class",f);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function v(e){return{height:e.offsetHeight,width:e.offsetWidth}}function m(i){var s=v(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function g(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function y(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function b(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function S(e){var t=g(e);return t>=E&&t<=w+E}function x(){var e=document.createElement("audio");e.setAttribute("class",c);e.src=i;e.loop=false;var t=false,n=false,r=false;e.addEventListener("timeupdate",function(){var i=e.currentTime,s=D,o=s.length,u;if(i>=.5&&!t){t=true;T(_)}if(i>=15.5&&!n){n=true;k();d();for(u=0;u<o;u++){N(s[u])}}if(e.currentTime>=28.4&&!r){r=true;C()}},true);e.addEventListener("ended",function(){k();p()},true);e.innerHTML="<p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p>";document.body.appendChild(e);e.play()}function T(e){e.className+=" "+s+" "+u}function N(e){e.className+=" "+s+" "+a[Math.floor(Math.random()*a.length)]}function C(){var e=document.getElementsByClassName(s);for(var t=0;t<e.length;){e[t].className=e[t].className.replace(s,o)}s=o}function k(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.ogg";var s="mw-harlem_shake_me";var o="mw-harlem_shake_slow";var u="im_first";var a=["im_drunk","im_baked","im_trippin","im_blown"];var f="mw-strobe_light";var l="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var c="mw_added_css";var w=y();var E=b();var L=document.getElementsByTagName("*"),A=L.length,O,M;var _=null;for(O=0;O<A;O++){M=L[O];if(m(M)){if(S(M)){_=M;break}}}if(M===null){console.warn("Could not find a node of the right size. Please try a different page.");return}h();x();var D=[];for(O=0;O<A;O++){M=L[O];if(m(M)){D.push(M)}}})()'>High一下!</a>
+</div>
+

其中的 href= 的内容替换为上述两种的其中一种即可。

+

修改目录位置到文章页左边

+

根据 sulvblog 的方法来改。

+

修改 toc.html

+

先修改 layouts/partials/toc.html 的代码,替换为:

+
{{- $headers := findRE "<h[1-6].*?>(.|\n])+?</h[1-6]>" .Content -}}
+{{- $has_headers := ge (len $headers) 1 -}}
+{{- if $has_headers -}}
+<aside id="toc-container" class="toc-container wide">
+    <div class="toc">
+        <details {{if (.Param "TocOpen") }} open{{ end }}>
+            <summary accesskey="c" title="(Alt + C)">
+                <span class="details">{{- i18n "toc" | default "Table of Contents" }}</span>
+            </summary>
+
+            <div class="inner">
+                {{- $largest := 6 -}}
+                {{- range $headers -}}
+                {{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
+                {{- $headerLevel := len (seq $headerLevel) -}}
+                {{- if lt $headerLevel $largest -}}
+                {{- $largest = $headerLevel -}}
+                {{- end -}}
+                {{- end -}}
+
+                {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}}
+
+                {{- $.Scratch.Set "bareul" slice -}}
+                <ul>
+                    {{- range seq (sub $firstHeaderLevel $largest) -}}
+                    <ul>
+                        {{- $.Scratch.Add "bareul" (sub (add $largest .) 1) -}}
+                        {{- end -}}
+                        {{- range $i, $header := $headers -}}
+                        {{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
+                        {{- $headerLevel := len (seq $headerLevel) -}}
+
+                        {{/* get id="xyz" */}}
+                        {{- $id := index (findRE "(id=\"(.*?)\")" $header 9) 0 }}
+
+                        {{- /* strip id="" to leave xyz, no way to get regex capturing groups in hugo */ -}}
+                        {{- $cleanedID := replace (replace $id "id=\"" "") "\"" "" }}
+                        {{- $header := replaceRE "<h[1-6].*?>((.|\n])+?)</h[1-6]>" "$1" $header -}}
+
+                        {{- if ne $i 0 -}}
+                        {{- $prevHeaderLevel := index (findRE "[1-6]" (index $headers (sub $i 1)) 1) 0 -}}
+                        {{- $prevHeaderLevel := len (seq $prevHeaderLevel) -}}
+                        {{- if gt $headerLevel $prevHeaderLevel -}}
+                        {{- range seq $prevHeaderLevel (sub $headerLevel 1) -}}
+                        <ul>
+                            {{/* the first should not be recorded */}}
+                            {{- if ne $prevHeaderLevel . -}}
+                            {{- $.Scratch.Add "bareul" . -}}
+                            {{- end -}}
+                            {{- end -}}
+                            {{- else -}}
+                            </li>
+                            {{- if lt $headerLevel $prevHeaderLevel -}}
+                            {{- range seq (sub $prevHeaderLevel 1) -1 $headerLevel -}}
+                            {{- if in ($.Scratch.Get "bareul") . -}}
+                        </ul>
+                        {{/* manually do pop item */}}
+                        {{- $tmp := $.Scratch.Get "bareul" -}}
+                        {{- $.Scratch.Delete "bareul" -}}
+                        {{- $.Scratch.Set "bareul" slice}}
+                        {{- range seq (sub (len $tmp) 1) -}}
+                        {{- $.Scratch.Add "bareul" (index $tmp (sub . 1)) -}}
+                        {{- end -}}
+                        {{- else -}}
+                    </ul>
+                    </li>
+                    {{- end -}}
+                    {{- end -}}
+                    {{- end -}}
+                    {{- end }}
+                    <li>
+                        <a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
+                        {{- else }}
+                    <li>
+                        <a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
+                        {{- end -}}
+                        {{- end -}}
+                        <!-- {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}} -->
+                        {{- $firstHeaderLevel := $largest }}
+                        {{- $lastHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers (sub (len $headers) 1)) 1) 0)) }}
+                    </li>
+                    {{- range seq (sub $lastHeaderLevel $firstHeaderLevel) -}}
+                    {{- if in ($.Scratch.Get "bareul") (add . $firstHeaderLevel) }}
+                </ul>
+                {{- else }}
+                </ul>
+                </li>
+                {{- end -}}
+                {{- end }}
+                </ul>
+            </div>
+        </details>
+    </div>
+</aside>
+<script>
+    let activeElement;
+    let elements;
+    window.addEventListener('DOMContentLoaded', function (event) {
+        checkTocPosition();
+
+        elements = document.querySelectorAll('h1[id],h2[id],h3[id],h4[id],h5[id],h6[id]');
+         // Make the first header active
+         activeElement = elements[0];
+         const id = encodeURI(activeElement.getAttribute('id')).toLowerCase();
+         document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
+     }, false);
+
+    window.addEventListener('resize', function(event) {
+        checkTocPosition();
+    }, false);
+
+    window.addEventListener('scroll', () => {
+        // Check if there is an object in the top half of the screen or keep the last item active
+        activeElement = Array.from(elements).find((element) => {
+            if ((getOffsetTop(element) - window.pageYOffset) > 0 && 
+                (getOffsetTop(element) - window.pageYOffset) < window.innerHeight/2) {
+                return element;
+            }
+        }) || activeElement
+
+        elements.forEach(element => {
+             const id = encodeURI(element.getAttribute('id')).toLowerCase();
+             if (element === activeElement){
+                 document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
+             } else {
+                 document.querySelector(`.inner ul li a[href="#${id}"]`).classList.remove('active');
+             }
+         })
+     }, false);
+
+    const main = parseInt(getComputedStyle(document.body).getPropertyValue('--article-width'), 10);
+    const toc = parseInt(getComputedStyle(document.body).getPropertyValue('--toc-width'), 10);
+    const gap = parseInt(getComputedStyle(document.body).getPropertyValue('--gap'), 10);
+
+    function checkTocPosition() {
+        const width = document.body.scrollWidth;
+
+        if (width - main - (toc * 2) - (gap * 4) > 0) {
+            document.getElementById("toc-container").classList.add("wide");
+        } else {
+            document.getElementById("toc-container").classList.remove("wide");
+        }
+    }
+
+    function getOffsetTop(element) {
+        if (!element.getClientRects().length) {
+            return 0;
+        }
+        let rect = element.getBoundingClientRect();
+        let win = element.ownerDocument.defaultView;
+        return rect.top + win.pageYOffset;   
+    }
+</script>
+{{- end }}
+

调用

+

layouts/_default/single.html 文件中默认有 toc.html 的调用,如果未更改的话不用管,更改的话请调用:

+
{{- if (.Param "ShowToc") }}
+{{- partial "toc.html" . }}
+{{- end }}
+

修改 css

+

修改 css/extended/blank.css 文件,加入下方代码:

+
:root {
+    --nav-width: 1380px;
+    --article-width: 650px;
+    --toc-width: 300px;
+}
+
+.toc {
+    margin: 0 2px 40px 2px;
+    border: 1px solid var(--border);
+    background: var(--entry);
+    border-radius: var(--radius);
+    padding: 0.4em;
+}
+
+.toc-container.wide {
+    position: absolute;
+    height: 100%;
+    border-right: 1px solid var(--border);
+    left: calc((var(--toc-width) + var(--gap)) * -1);
+    top: calc(var(--gap) * 2);
+    width: var(--toc-width);
+}
+
+.wide .toc {
+    position: sticky;
+    top: var(--gap);
+    border: unset;
+    background: unset;
+    border-radius: unset;
+    width: 100%;
+    margin: 0 2px 40px 2px;
+}
+
+.toc details summary {
+    cursor: zoom-in;
+    margin-inline-start: 20px;
+    padding: 12px 0;
+}
+
+.toc details[open] summary {
+    font-weight: 500;
+}
+
+.toc-container.wide .toc .inner {
+    margin: 0;
+}
+
+.active {
+    font-size: 110%;
+    font-weight: 600;
+}
+
+.toc ul {
+    list-style-type: circle;
+}
+
+.toc .inner {
+    margin: 0 0 0 20px;
+    padding: 0px 15px 15px 20px;
+    font-size: 16px;
+
+    /*目录显示高度*/
+    max-height: 83vh;
+    overflow-y: auto;
+}
+
+.toc .inner::-webkit-scrollbar-thumb {  /*滚动条*/
+    background: var(--border);
+    border: 7px solid var(--theme);
+    border-radius: var(--radius);
+}
+
+.toc li ul {
+    margin-inline-start: calc(var(--gap) * 0.5);
+    list-style-type: none;
+}
+
+.toc li {
+    list-style: none;
+    font-size: 0.95rem;
+    padding-bottom: 5px;
+}
+
+.toc li a:hover {
+    color: var(--secondary);
+}
+

重新编译后即可看到目录到了左边。

+

修改主题内容宽度

+

修改 ·assets\css\core\theme-vars.css 文件的 :root 节点中的 --main-width 我设置的是 1024px

+

修改代码块

+

修改渲染方式

+

放弃主题默认的 Highlight.js,改为 Hugo 默认的 chroma 方式渲染。根据 官方说明 来改。我用的 style 为 github-dark

+

设置代码块最大高度

+

assets\css\common\post-single.css 文件中找到 .post-content code 增加 max-height: 40em; 。目前设置好最大高度后会与 lineNos: true 设置冲突,会显示两个滑动条 :( ,所以就先不开它。

+

修改文章列表显示的图片位置

+

默认显示的图片在摘要上方而且很大,一页只能显示几个,感觉体验不是很好,所以将它改为在摘要右方显示。我很喜欢 CoolShell 的文章页的显示方法,准备改成差不多样子的。

+

修改 list.html

+

文件为 layouts\_default\list.html 。默认的图片显示代码为:

+
{{- $isHidden := (site.Params.cover.hidden | default site.Params.cover.hiddenInList) }}
+{{- partial "cover.html" (dict "cxt" . "IsHome" true "isHidden" $isHidden) }}
+

位于 <header class="entry-header"> 的上方。将其移动到 <div class="entry-content"> 中并替换默认的 Summary 处理方式,如下所示:

+
<div class="entry-content">
+    {{- $isHidden := (site.Params.cover.hidden | default site.Params.cover.hiddenInList) }}
+    {{- partial "cover.html" (dict "cxt" . "IsHome" true "isHidden" $isHidden) }}
+    {{ .Summary | replaceRE "\n" "<br>" | safeHTML }}{{ if .Truncated }}...{{ end }}
+</div>
+

修改 cover.html

+

文件为 layouts\partials\cover.html 。将 所有 <img 块都加上 align="right" 。完整如下所示:

+
{{- with .cxt}} {{/* Apply proper context from dict */}}
+{{- if (and .Params.cover.image (not $.isHidden)) }}
+{{- $alt := (.Params.cover.alt | default .Params.cover.caption | plainify) }}
+<figure class="entry-cover">
+    {{- $responsiveImages := (.Params.cover.responsiveImages | default site.Params.cover.responsiveImages) | default true }}
+    {{- $addLink := (and site.Params.cover.linkFullImages (not $.IsHome)) }}
+    {{- $pageBundleCover     := (.Resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
+    {{- $globalResourcesCover := (resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
+    {{- $cover := (or $pageBundleCover $globalResourcesCover)}}
+    {{- if $cover -}}{{/* i.e it is present in page bundle */}}
+        {{- if $addLink }}<a href="{{ (path.Join .RelPermalink .Params.cover.image) | absURL }}" target="_blank"
+            rel="noopener noreferrer">{{ end -}}
+        {{- $sizes := (slice "360" "480" "720" "1080" "1500") }}
+        {{- $processableFormats := (slice "jpg" "jpeg" "png" "tif" "bmp" "gif") -}}
+        {{- if hugo.IsExtended -}}
+            {{- $processableFormats = $processableFormats | append "webp" -}}
+        {{- end -}}
+        {{- $prod := (hugo.IsProduction | or (eq site.Params.env "production")) }}
+        {{- if (and (in $processableFormats $cover.MediaType.SubType) ($responsiveImages) (eq $prod true)) }}
+        <img loading="lazy" align="right" srcset="{{- range $size := $sizes -}}
+                        {{- if (ge $cover.Width $size) -}}
+                        {{ printf "%s %s" (($cover.Resize (printf "%sx" $size)).Permalink) (printf "%sw ," $size) -}}
+                        {{ end }}
+                    {{- end -}}{{$cover.Permalink }} {{printf "%dw" ($cover.Width)}}" 
+            sizes="(min-width: 768px) 720px, 100vw" src="{{ $cover.Permalink }}" alt="{{ $alt }}" 
+            width="{{ $cover.Width }}" height="{{ $cover.Height }}">
+        {{- else }}{{/* Unprocessable image or responsive images disabled */}}
+        <img loading="lazy" align="right" src="{{ (path.Join .RelPermalink .Params.cover.image) | absURL }}" alt="{{ $alt }}">
+        {{- end }}
+    {{- else }}{{/* For absolute urls and external links, no img processing here */}}
+        {{- if $addLink }}<a href="{{ (.Params.cover.image) | absURL }}" target="_blank"
+            rel="noopener noreferrer">{{ end -}}
+            <img loading="lazy" align="right" src="{{ (.Params.cover.image) | absURL }}" alt="{{ $alt }}">
+    {{- end }}
+    {{- if $addLink }}</a>{{ end -}}
+    {{/*  Display Caption  */}}
+    {{- if not $.IsHome }}
+        {{ with .Params.cover.caption }}<p>{{ . | markdownify }}</p>{{- end }}
+    {{- end }}
+</figure>
+{{- end }}{{/* End image */}}
+{{- end -}}{{/* End context */ -}}
+

增加 css

+

在文件 assets\css\extended\blank.css 中增加以下代码:

+
.entry-cover {
+    float:right;
+    width: 20%;
+    margin-left: 20px;
+}
+
+.entry-content {
+    margin: 20px 0;
+    color: var(--secondary);
+    font-size: 14px;
+    line-height: 1.6;
+    overflow: hidden;
+    display: block;
+}
+

这样做完的效果就是文章列表页的摘要可以自由显示文字和图片,默认的 cover 在文字右边,文字会环绕图片显示。

+

标签页词云效果

+

根据 Sulv’s Blog 的方法来改。

+

修改 terms.html

+

layouts/_default/terms.html 中的 <ul class="terms-tags"> 代码块替换为:

+
<ul class="terms-tags">
+    {{- $type := .Type }}
+    {{- range $key, $value := .Data.Terms.Alphabetical }}
+    {{- $name := .Name }}
+    {{- $count := .Count }}
+    {{- with $.Site.GetPage (printf "/%s/%s" $type $name) }}
+    <li>
+        {{ $largestFontSize := 1.5 }}
+        {{ $smallestFontSize := 1 }}
+        {{ $fontSpread := sub $largestFontSize $smallestFontSize }}
+        {{ $max := add (len (index $.Site.Taxonomies.tags.ByCount 0).Pages) 1 }}
+        {{ $min := len (index $.Site.Taxonomies.tags.ByCount.Reverse 0).Pages }}
+        {{ $spread := sub $max $min }}
+        {{ $fontStep := div $fontSpread $spread }}
+        {{ $weigth := div (sub (math.Log $count) (math.Log $min)) (sub (math.Log $max) (math.Log $min)) }}
+        {{ $currentFontSize := (add $smallestFontSize (mul (sub $largestFontSize $smallestFontSize) $weigth)) }}
+        <a href="{{ .Permalink }}" style="font-size: {{ $currentFontSize }}rem; font-weight: {{ mul $currentFontSize 200 }};">
+            {{ .Name }} <sup><strong><sup>{{ $count }}</sup></strong></sup>
+        </a>
+    </li>
+    {{- end }}
+    {{- end }}
+</ul>
+

增加 css

+

assets/css/extended/blank.css 中增加如下代码:

+
/*标签*/
+.terms-tags {
+    text-align: center;
+}
+
+.terms-tags a:hover {
+    background: none;
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.3);
+}
+
+.terms-tags a {
+    border-radius: 30px;
+    background: none;
+    transition: transform 0.5s;
+}
+
+.dark .terms-tags a {
+    background: none;
+}
+
+.dark .terms-tags a:hover {
+    background: none;
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.3);
+}
+
+.terms-tags li {
+    margin: 5px;
+}
+
]]>
+
+ + + 搭建博客 + https://blog.raikiriww.net/posts/%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2/ + Wed, 18 Oct 2023 22:20:34 +0800 + + https://blog.raikiriww.net/posts/%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2/ + <p>使用 Hugo 搭建博客。</p> + 使用 Hugo 搭建博客。

+

安装 Hugo

+

根据 Hugo 官网 的文档来安装 Hugo。

+

安装主题

+

我使用的主题为:hugo-PaperMod ,根据主题文档安装主题(推荐使用 submodule 的方式安装)。将默认的配置文件 hugo.toml 的后缀改为 yaml,方便使用。

+

主题配置

+

复制主题网站给的 Sample config.yml 的内容到 hugo.yaml 中,额外增加:

+
languageCode: zh
+defaultContentLanguage: zh
+

将网站语言设置为中文。

+

默认文章配置

+

复制 Sample Page.md 的内容到 archetypes/default.md 中(title 和 date 不覆盖,只将 toml 格式的配置改为 yaml 格式即可)。可以省去自己一个一个寻找增加的时间,当然,具体内容还是要根据自己的要求来改。

+

写文章

+

使用命令 hugo new content posts/my-first-post.md 来新建一篇文章。

+

本地预览

+

使用命令 hugo server -D 预览生成好的网页。

]]>
+
+ + + Python写入文件失败 + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + Wed, 11 Oct 2023 10:29:09 +0800 + + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + <p>公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。</p> + 公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

+

查找问题

+

大概的代码示例如下:

+
# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

从代码结构来看确实没什么问题,是先保存数据再降低电压,即使后边的操作导致死机也是在写入操作完成后,应该不会影响保存的数据才对。但事实是确实有影响,在 windows 上测试了好几次保存的数据都为空。with open() 语句是 Python 中常用的文件操作语句,不应该会导致写入异常,于是怀疑是降压操作导致的。

+

分析问题

+

在 Python 中,当使用 with open() 语句来写入文件时,它会负责管理文件的打开和关闭,通常情况下, with 语句块结束后,Python 会自动关闭文件,并确保所有数据写入硬盘。但,这个操作不是立即发生的。

+

当写入文件时,操作系统通常会缓存这些操作,以便一次性的将多个写入操作合并,从而提高效率。这意味着即使 Python 代码执行了写入操作(也就是 write()),也不能保证这些数据已经永久的保存到了硬盘上。如果在 with 语句块结束后立即死机,这些数据可能会丢失。

+

解决方法

+

现在知道了导致数据保存失败的原因是出在 windows 的系统缓存机制上,那只要找到方法可以强制系统将缓存的数据写入硬盘就好了。修改后的代码如下:

+
# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+  
+    # 确保数据从 Python 的内部缓冲区写入操作系统的缓冲区
+    f.flush()
+  
+    # 确保数据从操作系统的缓冲区写入磁盘
+    os.fsync(f.fileno())
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

新增了两行代码。

+
    +
  • f.flush() 的作用为刷新 Python 的内部缓冲区,确保所有数据写入操作系统的缓冲区。但这个并不能保证操作系统会立刻将数据写入硬盘。
  • +
  • os.fsync(f.fileno()) 的作用为强制操作系统将其缓冲区的数据写入硬盘。这样就保证了如果之后的代码导致系统死机,这部分数据也会完整的保存在硬盘上。
  • +
+

将修改后的程序在 windows 上测试,数据每次都会完整的保存在硬盘上。

+

后记

+

在 Microsoft 的一篇官方文档中有提到 disk write caching ,也就是写入缓存,并给出了关闭的方法。

+

关于 disk write caching ,官方的描述为:

+
+

Additionally, turning disk write caching on may increase operating system performance; however, it may also result in the loss of information if a power failure, equipment failure, or software failure occurs.

+
+

确实与我遇到的情况一样。

+

还有一篇更详细一点的介绍:https://learn.microsoft.com/en-US/windows/client-management/client-tools/change-default-removal-policy-external-storage-media

+

总的来说 disk write caching 在一般情况下可以提高性能。但在需要确保极端情况下写入数据完整性时,可以考虑关闭或者手动强制写入。

]]>
+
+ +
+
diff --git a/posts/page/1/index.html b/posts/page/1/index.html new file mode 100644 index 00000000..1ffe529d --- /dev/null +++ b/posts/page/1/index.html @@ -0,0 +1 @@ +https://blog.raikiriww.net/posts/ \ No newline at end of file diff --git "a/posts/python\345\206\231\345\205\245\346\226\207\344\273\266\345\244\261\350\264\245/index.html" "b/posts/python\345\206\231\345\205\245\346\226\207\344\273\266\345\244\261\350\264\245/index.html" new file mode 100644 index 00000000..cfb213c9 --- /dev/null +++ "b/posts/python\345\206\231\345\205\245\346\226\207\344\273\266\345\244\261\350\264\245/index.html" @@ -0,0 +1,24 @@ +Python写入文件失败 | raikiriww's blog
High一下!

Python写入文件失败

公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

查找问题

大概的代码示例如下:

# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

从代码结构来看确实没什么问题,是先保存数据再降低电压,即使后边的操作导致死机也是在写入操作完成后,应该不会影响保存的数据才对。但事实是确实有影响,在 windows 上测试了好几次保存的数据都为空。with open() 语句是 Python 中常用的文件操作语句,不应该会导致写入异常,于是怀疑是降压操作导致的。

分析问题

在 Python 中,当使用 with open() 语句来写入文件时,它会负责管理文件的打开和关闭,通常情况下, with 语句块结束后,Python 会自动关闭文件,并确保所有数据写入硬盘。但,这个操作不是立即发生的。

当写入文件时,操作系统通常会缓存这些操作,以便一次性的将多个写入操作合并,从而提高效率。这意味着即使 Python 代码执行了写入操作(也就是 write()),也不能保证这些数据已经永久的保存到了硬盘上。如果在 with 语句块结束后立即死机,这些数据可能会丢失。

解决方法

现在知道了导致数据保存失败的原因是出在 windows 的系统缓存机制上,那只要找到方法可以强制系统将缓存的数据写入硬盘就好了。修改后的代码如下:

# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+  
+    # 确保数据从 Python 的内部缓冲区写入操作系统的缓冲区
+    f.flush()
+  
+    # 确保数据从操作系统的缓冲区写入磁盘
+    os.fsync(f.fileno())
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

新增了两行代码。

  • f.flush() 的作用为刷新 Python 的内部缓冲区,确保所有数据写入操作系统的缓冲区。但这个并不能保证操作系统会立刻将数据写入硬盘。
  • os.fsync(f.fileno()) 的作用为强制操作系统将其缓冲区的数据写入硬盘。这样就保证了如果之后的代码导致系统死机,这部分数据也会完整的保存在硬盘上。

将修改后的程序在 windows 上测试,数据每次都会完整的保存在硬盘上。

后记

在 Microsoft 的一篇官方文档中有提到 disk write caching ,也就是写入缓存,并给出了关闭的方法。

关于 disk write caching ,官方的描述为:

Additionally, turning disk write caching on may increase operating system performance; however, it may also result in the loss of information if a power failure, equipment failure, or software failure occurs.

确实与我遇到的情况一样。

还有一篇更详细一点的介绍:https://learn.microsoft.com/en-US/windows/client-management/client-tools/change-default-removal-policy-external-storage-media

总的来说 disk write caching 在一般情况下可以提高性能。但在需要确保极端情况下写入数据完整性时,可以考虑关闭或者手动强制写入。

\ No newline at end of file diff --git "a/posts/\344\275\277\347\224\250-github-actions-\350\207\252\345\212\250\351\203\250\347\275\262\345\215\232\345\256\242/index.html" "b/posts/\344\275\277\347\224\250-github-actions-\350\207\252\345\212\250\351\203\250\347\275\262\345\215\232\345\256\242/index.html" new file mode 100644 index 00000000..5addc010 --- /dev/null +++ "b/posts/\344\275\277\347\224\250-github-actions-\350\207\252\345\212\250\351\203\250\347\275\262\345\215\232\345\256\242/index.html" @@ -0,0 +1,45 @@ +使用 Github Actions 自动部署博客 | raikiriww's blog
High一下!

使用 Github Actions 自动部署博客

利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。

Github token

具体位置为:个人设置界面 -> Developer Settings -> Personal access tokens -> Tokens(classic) 在此界面新生成一个 token,需要勾选 repoworkflow 选项。Expiration 可以设置为 No expiration 。创建完成后会显示你的 token ,它只会显示这一次,你需要将它记下来,后边会用到。

workflow 文件

想利用 Github Actions ,需要在博客的根目录下创建 .github/workflows/ 文件夹。在该文件夹下创建 yml 文件会被 Github Actions 执行。

我的 workflow 文件如下:

name: GitHub Pages
+
+on:
+  push:
+    branches:
+      - main  # Set a branch to deploy
+  
+    release:
+      types:
+        - published
+jobs:
+  deploy:
+    runs-on: ubuntu-20.04
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: main
+
+      - name: Setup Hugo
+        uses: peaceiris/actions-hugo@v2
+        with:
+          hugo-version: '0.119.0'
+          # 是否启用 hugo extend
+          # extended: true
+
+      - name: Build
+        run: hugo --minify
+
+      - name: Deploy
+        run: |
+          cd ./public
+          git init
+          git config --global user.name '${{ secrets.GITHUBUSERNAME }}'
+          git config --global user.email '${{ secrets.GITHUBEMAIL }}'
+          git add .
+          git commit -m "${{ github.event.head_commit.message }}"
+          git push --force --quiet "https://${{ secrets.GITHUBUSERNAME }}:${{ secrets.GITHUBTOKEN }}@github.com/${{ secrets.GITHUBUSERNAME }}/${{ secrets.GITHUBUSERNAME }}.github.io.git" master:main
+          #git push --force --quiet "https://${{ secrets.TOKENUSER }}:${{ secrets.CODINGTOKEN }}@e.coding.net/${{ secrets.CODINGUSERNAME }}/${{  secrets.CODINGBLOGREPO }}.git" master:master #coding部署写法,需要的自行取消注释
+          #git push --force --quiet "https://${{ secrets.GITEEUSERNAME }}:${{ secrets.GITEETOKEN }}@gitee.com/${{ secrets.GITEEUSERNAME }}/${{ secrets.GITEEUSERNAME }}.git" master:master #gitee部署写法,需要的自行取消注释          
+

其中,GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN 三个为自定义变量,后边会讲到。

源码仓库

新建或使用一个老的仓库,可见性设置为 private 。在代码仓库的 Settings 页面找到 Secrets and variables ,点击其中的 Actions ,添加 workflow 中用到的三个变量:GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN

action-secrets-settings

上传代码

完成上述步骤后即可用 git 提交代码到你的源码仓库,即可在仓库的 Actions 界面看到执行的 workflows。

参考

\ No newline at end of file diff --git "a/posts/\344\275\277\347\224\250-github-pages-\350\207\252\345\212\250\351\203\250\347\275\262\345\215\232\345\256\242/index.html" "b/posts/\344\275\277\347\224\250-github-pages-\350\207\252\345\212\250\351\203\250\347\275\262\345\215\232\345\256\242/index.html" new file mode 100644 index 00000000..e92cfbc3 --- /dev/null +++ "b/posts/\344\275\277\347\224\250-github-pages-\350\207\252\345\212\250\351\203\250\347\275\262\345\215\232\345\256\242/index.html" @@ -0,0 +1,45 @@ +使用 Github Pages 自动部署博客 | raikiriww's blog
High一下!

使用 Github Pages 自动部署博客

利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。

Github token

具体位置为:个人设置界面 -> Developer Settings -> Personal access tokens -> Tokens(classic) 在此界面新生成一个 token,需要勾选 repoworkflow 选项。Expiration 可以设置为 No expiration 。创建完成后会显示你的 token ,它只会显示这一次,你需要将它记下来,后边会用到。

workflow 文件

想利用 Github Actions ,需要在博客的根目录下创建 .github/workflows/ 文件夹。在该文件夹下创建 yml 文件会被 Github Actions 执行。

我的 workflow 文件如下:

name: GitHub Pages
+
+on:
+  push:
+    branches:
+      - main  # Set a branch to deploy
+      
+    release:
+      types:
+        - published
+jobs:
+  deploy:
+    runs-on: ubuntu-20.04
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: main
+
+      - name: Setup Hugo
+        uses: peaceiris/actions-hugo@v2
+        with:
+          hugo-version: 'latest'
+          # 是否启用 hugo extend
+          # extended: true
+
+      - name: Build
+        run: hugo --minify
+
+      - name: Deploy
+        run: |
+          cd ./public
+          git init
+          git config --global user.name '${{ secrets.GITHUBUSERNAME }}'
+          git config --global user.email '${{ secrets.GITHUBEMAIL }}'
+          git add .
+          git commit -m "${{ github.event.head_commit.message }}"
+          git push --force --quiet "https://${{ secrets.GITHUBUSERNAME }}:${{ secrets.GITHUBTOKEN }}@github.com/${{ secrets.GITHUBUSERNAME }}/${{ secrets.GITHUBUSERNAME }}.github.io.git" master:main
+          #git push --force --quiet "https://${{ secrets.TOKENUSER }}:${{ secrets.CODINGTOKEN }}@e.coding.net/${{ secrets.CODINGUSERNAME }}/${{  secrets.CODINGBLOGREPO }}.git" master:master #coding部署写法,需要的自行取消注释
+          #git push --force --quiet "https://${{ secrets.GITEEUSERNAME }}:${{ secrets.GITEETOKEN }}@gitee.com/${{ secrets.GITEEUSERNAME }}/${{ secrets.GITEEUSERNAME }}.git" master:master #gitee部署写法,需要的自行取消注释          
+

其中,GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN 三个为自定义变量,后边会讲到。

源码仓库

新建或使用一个老的仓库,可见性设置为 private 。在代码仓库的 Settings 页面找到 Secrets and variables ,点击其中的 Actions ,添加 workflow 中用到的三个变量:GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN

action-secrets-settings

上传代码

完成上述步骤后即可用 git 提交代码到你的源码仓库,即可在仓库的 Actions 界面看到执行的 workflows。

参考

\ No newline at end of file diff --git "a/posts/\346\220\255\345\273\272\345\215\232\345\256\242/index.html" "b/posts/\346\220\255\345\273\272\345\215\232\345\256\242/index.html" new file mode 100644 index 00000000..99b96d77 --- /dev/null +++ "b/posts/\346\220\255\345\273\272\345\215\232\345\256\242/index.html" @@ -0,0 +1,7 @@ +搭建博客 | raikiriww's blog
High一下!

搭建博客

使用 Hugo 搭建博客。

安装 Hugo

根据 Hugo 官网 的文档来安装 Hugo。

安装主题

我使用的主题为:hugo-PaperMod ,根据主题文档安装主题(推荐使用 submodule 的方式安装)。将默认的配置文件 hugo.toml 的后缀改为 yaml,方便使用。

主题配置

复制主题网站给的 Sample config.yml 的内容到 hugo.yaml 中,额外增加:

languageCode: zh
+defaultContentLanguage: zh
+

将网站语言设置为中文。

默认文章配置

复制 Sample Page.md 的内容到 archetypes/default.md 中(title 和 date 不覆盖,只将 toml 格式的配置改为 yaml 格式即可)。可以省去自己一个一个寻找增加的时间,当然,具体内容还是要根据自己的要求来改。

写文章

使用命令 hugo new content posts/my-first-post.md 来新建一篇文章。

本地预览

使用命令 hugo server -D 预览生成好的网页。

\ No newline at end of file diff --git "a/posts/\350\207\252\345\256\232\344\271\211\345\215\232\345\256\242\344\270\273\351\242\230/index.html" "b/posts/\350\207\252\345\256\232\344\271\211\345\215\232\345\256\242\344\270\273\351\242\230/index.html" new file mode 100644 index 00000000..05017dcf --- /dev/null +++ "b/posts/\350\207\252\345\256\232\344\271\211\345\215\232\345\256\242\344\270\273\351\242\230/index.html" @@ -0,0 +1,406 @@ +自定义博客 | raikiriww's blog
High一下!

自定义博客

此篇博客介绍我的博客的修改内容和方法。我的主题为 hugo-PaperMod 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。

石蒜小组件

来自与 Github 。项目地址为: https://github.com/dsrkafuu/sakana-widget 。具体更改为在 /layouts/partials/extend_head.html 中加入如下代码:

<!--  石蒜组件 -->
+<style>
+    html .pull-right{
+        position: absolute;
+        right: 0;
+        top: 70px;
+        
+        transform-origin: 100% 100%; /* 从右下开始变换 */
+    }
+    html #sakana-widget{
+        position: fixed;
+        right: 50px;
+        bottom: 0;
+        
+        transform-origin: 100% 100%; /* 从右下开始变换 */
+}
+</style>
+<link
+rel="stylesheet"
+href="https://cdn.jsdelivr.net/npm/sakana-widget@2.4.1/lib/sakana.min.css"
+/>
+<div id="sakana-widget", style="z-index:999"></div>
+<script>
+function initSakanaWidget() {
+    new SakanaWidget().mount('#sakana-widget');
+}
+</script>
+<script
+async
+onload="initSakanaWidget()"
+src="https://cdn.jsdelivr.net/npm/sakana-widget@2.4.1/lib/sakana.min.js"
+></script>
+

重新编译后即可拥有可爱石蒜小组件。sakana

High 一下

有两种 High 一下的代码实现:

javascript:(function(){function c(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",f);e.setAttribute("class",l);document.body.appendChild(e)}function h(){var e=document.getElementsByClassName(l);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function p(){var e=document.createElement("div");e.setAttribute("class",a);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function d(e){return{height:e.offsetHeight,width:e.offsetWidth}}function v(i){var s=d(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function m(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function g(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function y(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function E(e){var t=m(e);return t>=w&&t<=b+w}function S(){var e=document.createElement("audio");e.setAttribute("class",l);e.src=i;e.loop=false;e.addEventListener("canplay",function(){setTimeout(function(){x(k)},500);setTimeout(function(){N();p();for(var e=0;e<O.length;e++){T(O[e])}},15500)},true);e.addEventListener("ended",function(){N();h()},true);e.innerHTML=" <p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p> <p>";document.body.appendChild(e);e.play()}function x(e){e.className+=" "+s+" "+o}function T(e){e.className+=" "+s+" "+u[Math.floor(Math.random()*u.length)]}function N(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.mp3";var s="mw-harlem_shake_me";var o="im_first";var u=["im_drunk","im_baked","im_trippin","im_blown"];var a="mw-strobe_light";var f="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var l="mw_added_css";var b=g();var w=y();var C=document.getElementsByTagName("*");var k=null;for(var L=0;L<C.length;L++){var A=C[L];if(v(A)){if(E(A)){k=A;break}}}if(A===null){console.warn("Could not find a node of the right size. Please try a different page.");return}c();S();var O=[];for(var L=0;L<C.length;L++){var A=C[L];if(v(A)){O.push(A)}}})()
+
  • 第二种:来自于 Github 的 代码 :
javascript:(function(){function h(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",l);e.setAttribute("class",c);document.body.appendChild(e)}function p(){var e=document.getElementsByClassName(c);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function d(){var e=document.createElement("div");e.setAttribute("class",f);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function v(e){return{height:e.offsetHeight,width:e.offsetWidth}}function m(i){var s=v(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function g(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function y(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function b(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function S(e){var t=g(e);return t>=E&&t<=w+E}function x(){var e=document.createElement("audio");e.setAttribute("class",c);e.src=i;e.loop=false;var t=false,n=false,r=false;e.addEventListener("timeupdate",function(){var i=e.currentTime,s=D,o=s.length,u;if(i>=.5&&!t){t=true;T(_)}if(i>=15.5&&!n){n=true;k();d();for(u=0;u<o;u++){N(s[u])}}if(e.currentTime>=28.4&&!r){r=true;C()}},true);e.addEventListener("ended",function(){k();p()},true);e.innerHTML="<p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p>";document.body.appendChild(e);e.play()}function T(e){e.className+=" "+s+" "+u}function N(e){e.className+=" "+s+" "+a[Math.floor(Math.random()*a.length)]}function C(){var e=document.getElementsByClassName(s);for(var t=0;t<e.length;){e[t].className=e[t].className.replace(s,o)}s=o}function k(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.ogg";var s="mw-harlem_shake_me";var o="mw-harlem_shake_slow";var u="im_first";var a=["im_drunk","im_baked","im_trippin","im_blown"];var f="mw-strobe_light";var l="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var c="mw_added_css";var w=y();var E=b();var L=document.getElementsByTagName("*"),A=L.length,O,M;var _=null;for(O=0;O<A;O++){M=L[O];if(m(M)){if(S(M)){_=M;break}}}if(M===null){console.warn("Could not find a node of the right size. Please try a different page.");return}h();x();var D=[];for(O=0;O<A;O++){M=L[O];if(m(M)){D.push(M)}}})()
+

以上两种差不多,我个人用的是第二种。具体用法为在 /layouts/partials/extend_head.html 中加入如下代码:

<!--  High 一下 --> 
+<div class="pull-right", style="z-index:999">
+<a title="把这个链接拖到你的Chrome收藏夹工具栏中" href='javascript:(function(){function h(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",l);e.setAttribute("class",c);document.body.appendChild(e)}function p(){var e=document.getElementsByClassName(c);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function d(){var e=document.createElement("div");e.setAttribute("class",f);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function v(e){return{height:e.offsetHeight,width:e.offsetWidth}}function m(i){var s=v(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function g(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function y(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function b(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function S(e){var t=g(e);return t>=E&&t<=w+E}function x(){var e=document.createElement("audio");e.setAttribute("class",c);e.src=i;e.loop=false;var t=false,n=false,r=false;e.addEventListener("timeupdate",function(){var i=e.currentTime,s=D,o=s.length,u;if(i>=.5&&!t){t=true;T(_)}if(i>=15.5&&!n){n=true;k();d();for(u=0;u<o;u++){N(s[u])}}if(e.currentTime>=28.4&&!r){r=true;C()}},true);e.addEventListener("ended",function(){k();p()},true);e.innerHTML="<p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p>";document.body.appendChild(e);e.play()}function T(e){e.className+=" "+s+" "+u}function N(e){e.className+=" "+s+" "+a[Math.floor(Math.random()*a.length)]}function C(){var e=document.getElementsByClassName(s);for(var t=0;t<e.length;){e[t].className=e[t].className.replace(s,o)}s=o}function k(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.ogg";var s="mw-harlem_shake_me";var o="mw-harlem_shake_slow";var u="im_first";var a=["im_drunk","im_baked","im_trippin","im_blown"];var f="mw-strobe_light";var l="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var c="mw_added_css";var w=y();var E=b();var L=document.getElementsByTagName("*"),A=L.length,O,M;var _=null;for(O=0;O<A;O++){M=L[O];if(m(M)){if(S(M)){_=M;break}}}if(M===null){console.warn("Could not find a node of the right size. Please try a different page.");return}h();x();var D=[];for(O=0;O<A;O++){M=L[O];if(m(M)){D.push(M)}}})()'>High一下!</a>
+</div>
+

其中的 href= 的内容替换为上述两种的其中一种即可。

修改目录位置到文章页左边

根据 sulvblog 的方法来改。

修改 toc.html

先修改 layouts/partials/toc.html 的代码,替换为:

{{- $headers := findRE "<h[1-6].*?>(.|\n])+?</h[1-6]>" .Content -}}
+{{- $has_headers := ge (len $headers) 1 -}}
+{{- if $has_headers -}}
+<aside id="toc-container" class="toc-container wide">
+    <div class="toc">
+        <details {{if (.Param "TocOpen") }} open{{ end }}>
+            <summary accesskey="c" title="(Alt + C)">
+                <span class="details">{{- i18n "toc" | default "Table of Contents" }}</span>
+            </summary>
+
+            <div class="inner">
+                {{- $largest := 6 -}}
+                {{- range $headers -}}
+                {{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
+                {{- $headerLevel := len (seq $headerLevel) -}}
+                {{- if lt $headerLevel $largest -}}
+                {{- $largest = $headerLevel -}}
+                {{- end -}}
+                {{- end -}}
+
+                {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}}
+
+                {{- $.Scratch.Set "bareul" slice -}}
+                <ul>
+                    {{- range seq (sub $firstHeaderLevel $largest) -}}
+                    <ul>
+                        {{- $.Scratch.Add "bareul" (sub (add $largest .) 1) -}}
+                        {{- end -}}
+                        {{- range $i, $header := $headers -}}
+                        {{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
+                        {{- $headerLevel := len (seq $headerLevel) -}}
+
+                        {{/* get id="xyz" */}}
+                        {{- $id := index (findRE "(id=\"(.*?)\")" $header 9) 0 }}
+
+                        {{- /* strip id="" to leave xyz, no way to get regex capturing groups in hugo */ -}}
+                        {{- $cleanedID := replace (replace $id "id=\"" "") "\"" "" }}
+                        {{- $header := replaceRE "<h[1-6].*?>((.|\n])+?)</h[1-6]>" "$1" $header -}}
+
+                        {{- if ne $i 0 -}}
+                        {{- $prevHeaderLevel := index (findRE "[1-6]" (index $headers (sub $i 1)) 1) 0 -}}
+                        {{- $prevHeaderLevel := len (seq $prevHeaderLevel) -}}
+                        {{- if gt $headerLevel $prevHeaderLevel -}}
+                        {{- range seq $prevHeaderLevel (sub $headerLevel 1) -}}
+                        <ul>
+                            {{/* the first should not be recorded */}}
+                            {{- if ne $prevHeaderLevel . -}}
+                            {{- $.Scratch.Add "bareul" . -}}
+                            {{- end -}}
+                            {{- end -}}
+                            {{- else -}}
+                            </li>
+                            {{- if lt $headerLevel $prevHeaderLevel -}}
+                            {{- range seq (sub $prevHeaderLevel 1) -1 $headerLevel -}}
+                            {{- if in ($.Scratch.Get "bareul") . -}}
+                        </ul>
+                        {{/* manually do pop item */}}
+                        {{- $tmp := $.Scratch.Get "bareul" -}}
+                        {{- $.Scratch.Delete "bareul" -}}
+                        {{- $.Scratch.Set "bareul" slice}}
+                        {{- range seq (sub (len $tmp) 1) -}}
+                        {{- $.Scratch.Add "bareul" (index $tmp (sub . 1)) -}}
+                        {{- end -}}
+                        {{- else -}}
+                    </ul>
+                    </li>
+                    {{- end -}}
+                    {{- end -}}
+                    {{- end -}}
+                    {{- end }}
+                    <li>
+                        <a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
+                        {{- else }}
+                    <li>
+                        <a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
+                        {{- end -}}
+                        {{- end -}}
+                        <!-- {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}} -->
+                        {{- $firstHeaderLevel := $largest }}
+                        {{- $lastHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers (sub (len $headers) 1)) 1) 0)) }}
+                    </li>
+                    {{- range seq (sub $lastHeaderLevel $firstHeaderLevel) -}}
+                    {{- if in ($.Scratch.Get "bareul") (add . $firstHeaderLevel) }}
+                </ul>
+                {{- else }}
+                </ul>
+                </li>
+                {{- end -}}
+                {{- end }}
+                </ul>
+            </div>
+        </details>
+    </div>
+</aside>
+<script>
+    let activeElement;
+    let elements;
+    window.addEventListener('DOMContentLoaded', function (event) {
+        checkTocPosition();
+
+        elements = document.querySelectorAll('h1[id],h2[id],h3[id],h4[id],h5[id],h6[id]');
+         // Make the first header active
+         activeElement = elements[0];
+         const id = encodeURI(activeElement.getAttribute('id')).toLowerCase();
+         document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
+     }, false);
+
+    window.addEventListener('resize', function(event) {
+        checkTocPosition();
+    }, false);
+
+    window.addEventListener('scroll', () => {
+        // Check if there is an object in the top half of the screen or keep the last item active
+        activeElement = Array.from(elements).find((element) => {
+            if ((getOffsetTop(element) - window.pageYOffset) > 0 && 
+                (getOffsetTop(element) - window.pageYOffset) < window.innerHeight/2) {
+                return element;
+            }
+        }) || activeElement
+
+        elements.forEach(element => {
+             const id = encodeURI(element.getAttribute('id')).toLowerCase();
+             if (element === activeElement){
+                 document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
+             } else {
+                 document.querySelector(`.inner ul li a[href="#${id}"]`).classList.remove('active');
+             }
+         })
+     }, false);
+
+    const main = parseInt(getComputedStyle(document.body).getPropertyValue('--article-width'), 10);
+    const toc = parseInt(getComputedStyle(document.body).getPropertyValue('--toc-width'), 10);
+    const gap = parseInt(getComputedStyle(document.body).getPropertyValue('--gap'), 10);
+
+    function checkTocPosition() {
+        const width = document.body.scrollWidth;
+
+        if (width - main - (toc * 2) - (gap * 4) > 0) {
+            document.getElementById("toc-container").classList.add("wide");
+        } else {
+            document.getElementById("toc-container").classList.remove("wide");
+        }
+    }
+
+    function getOffsetTop(element) {
+        if (!element.getClientRects().length) {
+            return 0;
+        }
+        let rect = element.getBoundingClientRect();
+        let win = element.ownerDocument.defaultView;
+        return rect.top + win.pageYOffset;   
+    }
+</script>
+{{- end }}
+

调用

layouts/_default/single.html 文件中默认有 toc.html 的调用,如果未更改的话不用管,更改的话请调用:

{{- if (.Param "ShowToc") }}
+{{- partial "toc.html" . }}
+{{- end }}
+

修改 css

修改 css/extended/blank.css 文件,加入下方代码:

:root {
+    --nav-width: 1380px;
+    --article-width: 650px;
+    --toc-width: 300px;
+}
+
+.toc {
+    margin: 0 2px 40px 2px;
+    border: 1px solid var(--border);
+    background: var(--entry);
+    border-radius: var(--radius);
+    padding: 0.4em;
+}
+
+.toc-container.wide {
+    position: absolute;
+    height: 100%;
+    border-right: 1px solid var(--border);
+    left: calc((var(--toc-width) + var(--gap)) * -1);
+    top: calc(var(--gap) * 2);
+    width: var(--toc-width);
+}
+
+.wide .toc {
+    position: sticky;
+    top: var(--gap);
+    border: unset;
+    background: unset;
+    border-radius: unset;
+    width: 100%;
+    margin: 0 2px 40px 2px;
+}
+
+.toc details summary {
+    cursor: zoom-in;
+    margin-inline-start: 20px;
+    padding: 12px 0;
+}
+
+.toc details[open] summary {
+    font-weight: 500;
+}
+
+.toc-container.wide .toc .inner {
+    margin: 0;
+}
+
+.active {
+    font-size: 110%;
+    font-weight: 600;
+}
+
+.toc ul {
+    list-style-type: circle;
+}
+
+.toc .inner {
+    margin: 0 0 0 20px;
+    padding: 0px 15px 15px 20px;
+    font-size: 16px;
+
+    /*目录显示高度*/
+    max-height: 83vh;
+    overflow-y: auto;
+}
+
+.toc .inner::-webkit-scrollbar-thumb {  /*滚动条*/
+    background: var(--border);
+    border: 7px solid var(--theme);
+    border-radius: var(--radius);
+}
+
+.toc li ul {
+    margin-inline-start: calc(var(--gap) * 0.5);
+    list-style-type: none;
+}
+
+.toc li {
+    list-style: none;
+    font-size: 0.95rem;
+    padding-bottom: 5px;
+}
+
+.toc li a:hover {
+    color: var(--secondary);
+}
+

重新编译后即可看到目录到了左边。

修改主题内容宽度

修改 ·assets\css\core\theme-vars.css 文件的 :root 节点中的 --main-width 我设置的是 1024px

修改代码块

修改渲染方式

放弃主题默认的 Highlight.js,改为 Hugo 默认的 chroma 方式渲染。根据 官方说明 来改。我用的 style 为 github-dark

设置代码块最大高度

assets\css\common\post-single.css 文件中找到 .post-content code 增加 max-height: 40em; 。目前设置好最大高度后会与 lineNos: true 设置冲突,会显示两个滑动条 :( ,所以就先不开它。

修改文章列表显示的图片位置

默认显示的图片在摘要上方而且很大,一页只能显示几个,感觉体验不是很好,所以将它改为在摘要右方显示。我很喜欢 CoolShell 的文章页的显示方法,准备改成差不多样子的。

修改 list.html

文件为 layouts\_default\list.html 。默认的图片显示代码为:

{{- $isHidden := (site.Params.cover.hidden | default site.Params.cover.hiddenInList) }}
+{{- partial "cover.html" (dict "cxt" . "IsHome" true "isHidden" $isHidden) }}
+

位于 <header class="entry-header"> 的上方。将其移动到 <div class="entry-content"> 中并替换默认的 Summary 处理方式,如下所示:

<div class="entry-content">
+    {{- $isHidden := (site.Params.cover.hidden | default site.Params.cover.hiddenInList) }}
+    {{- partial "cover.html" (dict "cxt" . "IsHome" true "isHidden" $isHidden) }}
+    {{ .Summary | replaceRE "\n" "<br>" | safeHTML }}{{ if .Truncated }}...{{ end }}
+</div>
+

修改 cover.html

文件为 layouts\partials\cover.html 。将 所有 <img 块都加上 align="right" 。完整如下所示:

{{- with .cxt}} {{/* Apply proper context from dict */}}
+{{- if (and .Params.cover.image (not $.isHidden)) }}
+{{- $alt := (.Params.cover.alt | default .Params.cover.caption | plainify) }}
+<figure class="entry-cover">
+    {{- $responsiveImages := (.Params.cover.responsiveImages | default site.Params.cover.responsiveImages) | default true }}
+    {{- $addLink := (and site.Params.cover.linkFullImages (not $.IsHome)) }}
+    {{- $pageBundleCover     := (.Resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
+    {{- $globalResourcesCover := (resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
+    {{- $cover := (or $pageBundleCover $globalResourcesCover)}}
+    {{- if $cover -}}{{/* i.e it is present in page bundle */}}
+        {{- if $addLink }}<a href="{{ (path.Join .RelPermalink .Params.cover.image) | absURL }}" target="_blank"
+            rel="noopener noreferrer">{{ end -}}
+        {{- $sizes := (slice "360" "480" "720" "1080" "1500") }}
+        {{- $processableFormats := (slice "jpg" "jpeg" "png" "tif" "bmp" "gif") -}}
+        {{- if hugo.IsExtended -}}
+            {{- $processableFormats = $processableFormats | append "webp" -}}
+        {{- end -}}
+        {{- $prod := (hugo.IsProduction | or (eq site.Params.env "production")) }}
+        {{- if (and (in $processableFormats $cover.MediaType.SubType) ($responsiveImages) (eq $prod true)) }}
+        <img loading="lazy" align="right" srcset="{{- range $size := $sizes -}}
+                        {{- if (ge $cover.Width $size) -}}
+                        {{ printf "%s %s" (($cover.Resize (printf "%sx" $size)).Permalink) (printf "%sw ," $size) -}}
+                        {{ end }}
+                    {{- end -}}{{$cover.Permalink }} {{printf "%dw" ($cover.Width)}}" 
+            sizes="(min-width: 768px) 720px, 100vw" src="{{ $cover.Permalink }}" alt="{{ $alt }}" 
+            width="{{ $cover.Width }}" height="{{ $cover.Height }}">
+        {{- else }}{{/* Unprocessable image or responsive images disabled */}}
+        <img loading="lazy" align="right" src="{{ (path.Join .RelPermalink .Params.cover.image) | absURL }}" alt="{{ $alt }}">
+        {{- end }}
+    {{- else }}{{/* For absolute urls and external links, no img processing here */}}
+        {{- if $addLink }}<a href="{{ (.Params.cover.image) | absURL }}" target="_blank"
+            rel="noopener noreferrer">{{ end -}}
+            <img loading="lazy" align="right" src="{{ (.Params.cover.image) | absURL }}" alt="{{ $alt }}">
+    {{- end }}
+    {{- if $addLink }}</a>{{ end -}}
+    {{/*  Display Caption  */}}
+    {{- if not $.IsHome }}
+        {{ with .Params.cover.caption }}<p>{{ . | markdownify }}</p>{{- end }}
+    {{- end }}
+</figure>
+{{- end }}{{/* End image */}}
+{{- end -}}{{/* End context */ -}}
+

增加 css

在文件 assets\css\extended\blank.css 中增加以下代码:

.entry-cover {
+    float:right;
+    width: 20%;
+    margin-left: 20px;
+}
+
+.entry-content {
+    margin: 20px 0;
+    color: var(--secondary);
+    font-size: 14px;
+    line-height: 1.6;
+    overflow: hidden;
+    display: block;
+}
+

这样做完的效果就是文章列表页的摘要可以自由显示文字和图片,默认的 cover 在文字右边,文字会环绕图片显示。

标签页词云效果

根据 Sulv’s Blog 的方法来改。

修改 terms.html

layouts/_default/terms.html 中的 <ul class="terms-tags"> 代码块替换为:

<ul class="terms-tags">
+    {{- $type := .Type }}
+    {{- range $key, $value := .Data.Terms.Alphabetical }}
+    {{- $name := .Name }}
+    {{- $count := .Count }}
+    {{- with $.Site.GetPage (printf "/%s/%s" $type $name) }}
+    <li>
+        {{ $largestFontSize := 1.5 }}
+        {{ $smallestFontSize := 1 }}
+        {{ $fontSpread := sub $largestFontSize $smallestFontSize }}
+        {{ $max := add (len (index $.Site.Taxonomies.tags.ByCount 0).Pages) 1 }}
+        {{ $min := len (index $.Site.Taxonomies.tags.ByCount.Reverse 0).Pages }}
+        {{ $spread := sub $max $min }}
+        {{ $fontStep := div $fontSpread $spread }}
+        {{ $weigth := div (sub (math.Log $count) (math.Log $min)) (sub (math.Log $max) (math.Log $min)) }}
+        {{ $currentFontSize := (add $smallestFontSize (mul (sub $largestFontSize $smallestFontSize) $weigth)) }}
+        <a href="{{ .Permalink }}" style="font-size: {{ $currentFontSize }}rem; font-weight: {{ mul $currentFontSize 200 }};">
+            {{ .Name }} <sup><strong><sup>{{ $count }}</sup></strong></sup>
+        </a>
+    </li>
+    {{- end }}
+    {{- end }}
+</ul>
+

增加 css

assets/css/extended/blank.css 中增加如下代码:

/*标签*/
+.terms-tags {
+    text-align: center;
+}
+
+.terms-tags a:hover {
+    background: none;
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.3);
+}
+
+.terms-tags a {
+    border-radius: 30px;
+    background: none;
+    transition: transform 0.5s;
+}
+
+.dark .terms-tags a {
+    background: none;
+}
+
+.dark .terms-tags a:hover {
+    background: none;
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.3);
+}
+
+.terms-tags li {
+    margin: 5px;
+}
+
\ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 00000000..55e3885b --- /dev/null +++ b/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Disallow: +Sitemap: https://blog.raikiriww.net/sitemap.xml diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..f028aaa2 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,37 @@ + + + + https://blog.raikiriww.net/posts/ + 2023-10-20T21:33:25+08:00 + + https://blog.raikiriww.net/ + 2023-10-20T21:33:25+08:00 + + https://blog.raikiriww.net/tags/ + 2023-10-20T21:33:25+08:00 + + https://blog.raikiriww.net/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/ + 2023-10-20T21:33:25+08:00 + + https://blog.raikiriww.net/posts/%E4%BD%BF%E7%94%A8-github-actions-%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%8D%9A%E5%AE%A2/ + 2023-10-20T21:33:25+08:00 + + https://blog.raikiriww.net/posts/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98/ + 2023-10-18T22:29:02+08:00 + + https://blog.raikiriww.net/posts/%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2/ + 2023-10-18T22:20:34+08:00 + + https://blog.raikiriww.net/tags/python/ + 2023-10-11T10:29:09+08:00 + + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + 2023-10-11T10:29:09+08:00 + + https://blog.raikiriww.net/tags/%E6%8A%80%E6%9C%AF/ + 2023-10-11T10:29:09+08:00 + + https://blog.raikiriww.net/categories/ + + diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 00000000..2b8bc3de --- /dev/null +++ b/tags/index.html @@ -0,0 +1,4 @@ +Tags | raikiriww's blog
High一下!
\ No newline at end of file diff --git a/tags/index.xml b/tags/index.xml new file mode 100644 index 00000000..313acbf4 --- /dev/null +++ b/tags/index.xml @@ -0,0 +1,41 @@ + + + + Tags on raikiriww's blog + https://blog.raikiriww.net/tags/ + Recent content in Tags on raikiriww's blog + Hugo -- gohugo.io + zh + Fri, 20 Oct 2023 21:33:25 +0800 + + 博客搭建 + https://blog.raikiriww.net/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/ + Fri, 20 Oct 2023 21:33:25 +0800 + + https://blog.raikiriww.net/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/ + + + + + + Python + https://blog.raikiriww.net/tags/python/ + Wed, 11 Oct 2023 10:29:09 +0800 + + https://blog.raikiriww.net/tags/python/ + + + + + + 技术 + https://blog.raikiriww.net/tags/%E6%8A%80%E6%9C%AF/ + Wed, 11 Oct 2023 10:29:09 +0800 + + https://blog.raikiriww.net/tags/%E6%8A%80%E6%9C%AF/ + + + + + + diff --git a/tags/python/index.html b/tags/python/index.html new file mode 100644 index 00000000..5f347016 --- /dev/null +++ b/tags/python/index.html @@ -0,0 +1,5 @@ +Python | raikiriww's blog
High一下!

Python写入文件失败

公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

...
十月 11, 2023 · 1 分钟 · 143 字 · raikiriww
\ No newline at end of file diff --git a/tags/python/index.xml b/tags/python/index.xml new file mode 100644 index 00000000..0bd25f27 --- /dev/null +++ b/tags/python/index.xml @@ -0,0 +1,64 @@ + + + + Python on raikiriww's blog + https://blog.raikiriww.net/tags/python/ + Recent content in Python on raikiriww's blog + Hugo -- gohugo.io + zh + Wed, 11 Oct 2023 10:29:09 +0800 + + Python写入文件失败 + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + Wed, 11 Oct 2023 10:29:09 +0800 + + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + <p>公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。</p> + 公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

+

查找问题

+

大概的代码示例如下:

+
# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

从代码结构来看确实没什么问题,是先保存数据再降低电压,即使后边的操作导致死机也是在写入操作完成后,应该不会影响保存的数据才对。但事实是确实有影响,在 windows 上测试了好几次保存的数据都为空。with open() 语句是 Python 中常用的文件操作语句,不应该会导致写入异常,于是怀疑是降压操作导致的。

+

分析问题

+

在 Python 中,当使用 with open() 语句来写入文件时,它会负责管理文件的打开和关闭,通常情况下, with 语句块结束后,Python 会自动关闭文件,并确保所有数据写入硬盘。但,这个操作不是立即发生的。

+

当写入文件时,操作系统通常会缓存这些操作,以便一次性的将多个写入操作合并,从而提高效率。这意味着即使 Python 代码执行了写入操作(也就是 write()),也不能保证这些数据已经永久的保存到了硬盘上。如果在 with 语句块结束后立即死机,这些数据可能会丢失。

+

解决方法

+

现在知道了导致数据保存失败的原因是出在 windows 的系统缓存机制上,那只要找到方法可以强制系统将缓存的数据写入硬盘就好了。修改后的代码如下:

+
# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+  
+    # 确保数据从 Python 的内部缓冲区写入操作系统的缓冲区
+    f.flush()
+  
+    # 确保数据从操作系统的缓冲区写入磁盘
+    os.fsync(f.fileno())
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

新增了两行代码。

+
    +
  • f.flush() 的作用为刷新 Python 的内部缓冲区,确保所有数据写入操作系统的缓冲区。但这个并不能保证操作系统会立刻将数据写入硬盘。
  • +
  • os.fsync(f.fileno()) 的作用为强制操作系统将其缓冲区的数据写入硬盘。这样就保证了如果之后的代码导致系统死机,这部分数据也会完整的保存在硬盘上。
  • +
+

将修改后的程序在 windows 上测试,数据每次都会完整的保存在硬盘上。

+

后记

+

在 Microsoft 的一篇官方文档中有提到 disk write caching ,也就是写入缓存,并给出了关闭的方法。

+

关于 disk write caching ,官方的描述为:

+
+

Additionally, turning disk write caching on may increase operating system performance; however, it may also result in the loss of information if a power failure, equipment failure, or software failure occurs.

+
+

确实与我遇到的情况一样。

+

还有一篇更详细一点的介绍:https://learn.microsoft.com/en-US/windows/client-management/client-tools/change-default-removal-policy-external-storage-media

+

总的来说 disk write caching 在一般情况下可以提高性能。但在需要确保极端情况下写入数据完整性时,可以考虑关闭或者手动强制写入。

]]>
+
+ +
+
diff --git a/tags/python/page/1/index.html b/tags/python/page/1/index.html new file mode 100644 index 00000000..5b431ced --- /dev/null +++ b/tags/python/page/1/index.html @@ -0,0 +1 @@ +https://blog.raikiriww.net/tags/python/ \ No newline at end of file diff --git "a/tags/\345\215\232\345\256\242\346\220\255\345\273\272/index.html" "b/tags/\345\215\232\345\256\242\346\220\255\345\273\272/index.html" new file mode 100644 index 00000000..d946e0f5 --- /dev/null +++ "b/tags/\345\215\232\345\256\242\346\220\255\345\273\272/index.html" @@ -0,0 +1,5 @@ +博客搭建 | raikiriww's blog
High一下!

使用 Github Actions 自动部署博客

利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。

...
十月 20, 2023 · 1 分钟 · 213 字 · raikiriww

自定义博客

此篇博客介绍我的博客的修改内容和方法。我的主题为 hugo-PaperMod 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。

...
十月 18, 2023 · 10 分钟 · 1939 字 · raikiriww

搭建博客

使用 Hugo 搭建博客。

...
十月 18, 2023 · 1 分钟 · 57 字 · raikiriww
\ No newline at end of file diff --git "a/tags/\345\215\232\345\256\242\346\220\255\345\273\272/index.xml" "b/tags/\345\215\232\345\256\242\346\220\255\345\273\272/index.xml" new file mode 100644 index 00000000..8171b85e --- /dev/null +++ "b/tags/\345\215\232\345\256\242\346\220\255\345\273\272/index.xml" @@ -0,0 +1,562 @@ + + + + 博客搭建 on raikiriww's blog + https://blog.raikiriww.net/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/ + Recent content in 博客搭建 on raikiriww's blog + Hugo -- gohugo.io + zh + Fri, 20 Oct 2023 21:33:25 +0800 + + 使用 Github Actions 自动部署博客 + https://blog.raikiriww.net/posts/%E4%BD%BF%E7%94%A8-github-actions-%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%8D%9A%E5%AE%A2/ + Fri, 20 Oct 2023 21:33:25 +0800 + + https://blog.raikiriww.net/posts/%E4%BD%BF%E7%94%A8-github-actions-%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2%E5%8D%9A%E5%AE%A2/ + <p>利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。</p> + 利用 Github Actions 来自动构建和部署博客到 Github Pages。这样既可以简化自己的操作,又能保证自己的博客源码的私密性。

+

Github token

+

具体位置为:个人设置界面 -> Developer Settings -> Personal access tokens -> Tokens(classic) 在此界面新生成一个 token,需要勾选 repoworkflow 选项。Expiration 可以设置为 No expiration 。创建完成后会显示你的 token ,它只会显示这一次,你需要将它记下来,后边会用到。

+

workflow 文件

+

想利用 Github Actions ,需要在博客的根目录下创建 .github/workflows/ 文件夹。在该文件夹下创建 yml 文件会被 Github Actions 执行。

+

我的 workflow 文件如下:

+
name: GitHub Pages
+
+on:
+  push:
+    branches:
+      - main  # Set a branch to deploy
+  
+    release:
+      types:
+        - published
+jobs:
+  deploy:
+    runs-on: ubuntu-20.04
+    concurrency:
+      group: ${{ github.workflow }}-${{ github.ref }}
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          ref: main
+
+      - name: Setup Hugo
+        uses: peaceiris/actions-hugo@v2
+        with:
+          hugo-version: '0.119.0'
+          # 是否启用 hugo extend
+          # extended: true
+
+      - name: Build
+        run: hugo --minify
+
+      - name: Deploy
+        run: |
+          cd ./public
+          git init
+          git config --global user.name '${{ secrets.GITHUBUSERNAME }}'
+          git config --global user.email '${{ secrets.GITHUBEMAIL }}'
+          git add .
+          git commit -m "${{ github.event.head_commit.message }}"
+          git push --force --quiet "https://${{ secrets.GITHUBUSERNAME }}:${{ secrets.GITHUBTOKEN }}@github.com/${{ secrets.GITHUBUSERNAME }}/${{ secrets.GITHUBUSERNAME }}.github.io.git" master:main
+          #git push --force --quiet "https://${{ secrets.TOKENUSER }}:${{ secrets.CODINGTOKEN }}@e.coding.net/${{ secrets.CODINGUSERNAME }}/${{  secrets.CODINGBLOGREPO }}.git" master:master #coding部署写法,需要的自行取消注释
+          #git push --force --quiet "https://${{ secrets.GITEEUSERNAME }}:${{ secrets.GITEETOKEN }}@gitee.com/${{ secrets.GITEEUSERNAME }}/${{ secrets.GITEEUSERNAME }}.git" master:master #gitee部署写法,需要的自行取消注释          
+

其中,GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN 三个为自定义变量,后边会讲到。

+

源码仓库

+

新建或使用一个老的仓库,可见性设置为 private 。在代码仓库的 Settings 页面找到 Secrets and variables ,点击其中的 Actions ,添加 workflow 中用到的三个变量:GITHUBUSERNAMEGITHUBEMAILGITHUBTOKEN

+

action-secrets-settings +

+

上传代码

+

完成上述步骤后即可用 git 提交代码到你的源码仓库,即可在仓库的 Actions 界面看到执行的 workflows。

+

参考

+]]>
+
+ + + 自定义博客 + https://blog.raikiriww.net/posts/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98/ + Wed, 18 Oct 2023 22:29:02 +0800 + + https://blog.raikiriww.net/posts/%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8D%9A%E5%AE%A2%E4%B8%BB%E9%A2%98/ + <p>此篇博客介绍我的博客的修改内容和方法。我的主题为 <a href="https://github.com/adityatelange/hugo-PaperMod">hugo-PaperMod</a> 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。</p> + 此篇博客介绍我的博客的修改内容和方法。我的主题为 hugo-PaperMod 。我修改前都将博客内的资源文件夹(assets, i18n, lay)复制到了项目根目录中,这样以后更新主题也不会导致修改消失。

+

石蒜小组件

+

来自与 Github 。项目地址为: https://github.com/dsrkafuu/sakana-widget 。具体更改为在 /layouts/partials/extend_head.html 中加入如下代码:

+
<!--  石蒜组件 -->
+<style>
+    html .pull-right{
+        position: absolute;
+        right: 0;
+        top: 70px;
+        
+        transform-origin: 100% 100%; /* 从右下开始变换 */
+    }
+    html #sakana-widget{
+        position: fixed;
+        right: 50px;
+        bottom: 0;
+        
+        transform-origin: 100% 100%; /* 从右下开始变换 */
+}
+</style>
+<link
+rel="stylesheet"
+href="https://cdn.jsdelivr.net/npm/sakana-widget@2.4.1/lib/sakana.min.css"
+/>
+<div id="sakana-widget", style="z-index:999"></div>
+<script>
+function initSakanaWidget() {
+    new SakanaWidget().mount('#sakana-widget');
+}
+</script>
+<script
+async
+onload="initSakanaWidget()"
+src="https://cdn.jsdelivr.net/npm/sakana-widget@2.4.1/lib/sakana.min.js"
+></script>
+

重新编译后即可拥有可爱石蒜小组件。sakana +

+

High 一下

+

有两种 High 一下的代码实现:

+ +
javascript:(function(){function c(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",f);e.setAttribute("class",l);document.body.appendChild(e)}function h(){var e=document.getElementsByClassName(l);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function p(){var e=document.createElement("div");e.setAttribute("class",a);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function d(e){return{height:e.offsetHeight,width:e.offsetWidth}}function v(i){var s=d(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function m(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function g(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function y(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function E(e){var t=m(e);return t>=w&&t<=b+w}function S(){var e=document.createElement("audio");e.setAttribute("class",l);e.src=i;e.loop=false;e.addEventListener("canplay",function(){setTimeout(function(){x(k)},500);setTimeout(function(){N();p();for(var e=0;e<O.length;e++){T(O[e])}},15500)},true);e.addEventListener("ended",function(){N();h()},true);e.innerHTML=" <p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p> <p>";document.body.appendChild(e);e.play()}function x(e){e.className+=" "+s+" "+o}function T(e){e.className+=" "+s+" "+u[Math.floor(Math.random()*u.length)]}function N(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.mp3";var s="mw-harlem_shake_me";var o="im_first";var u=["im_drunk","im_baked","im_trippin","im_blown"];var a="mw-strobe_light";var f="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var l="mw_added_css";var b=g();var w=y();var C=document.getElementsByTagName("*");var k=null;for(var L=0;L<C.length;L++){var A=C[L];if(v(A)){if(E(A)){k=A;break}}}if(A===null){console.warn("Could not find a node of the right size. Please try a different page.");return}c();S();var O=[];for(var L=0;L<C.length;L++){var A=C[L];if(v(A)){O.push(A)}}})()
+
    +
  • 第二种:来自于 Github 的 代码 :
  • +
+
javascript:(function(){function h(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",l);e.setAttribute("class",c);document.body.appendChild(e)}function p(){var e=document.getElementsByClassName(c);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function d(){var e=document.createElement("div");e.setAttribute("class",f);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function v(e){return{height:e.offsetHeight,width:e.offsetWidth}}function m(i){var s=v(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function g(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function y(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function b(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function S(e){var t=g(e);return t>=E&&t<=w+E}function x(){var e=document.createElement("audio");e.setAttribute("class",c);e.src=i;e.loop=false;var t=false,n=false,r=false;e.addEventListener("timeupdate",function(){var i=e.currentTime,s=D,o=s.length,u;if(i>=.5&&!t){t=true;T(_)}if(i>=15.5&&!n){n=true;k();d();for(u=0;u<o;u++){N(s[u])}}if(e.currentTime>=28.4&&!r){r=true;C()}},true);e.addEventListener("ended",function(){k();p()},true);e.innerHTML="<p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p>";document.body.appendChild(e);e.play()}function T(e){e.className+=" "+s+" "+u}function N(e){e.className+=" "+s+" "+a[Math.floor(Math.random()*a.length)]}function C(){var e=document.getElementsByClassName(s);for(var t=0;t<e.length;){e[t].className=e[t].className.replace(s,o)}s=o}function k(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.ogg";var s="mw-harlem_shake_me";var o="mw-harlem_shake_slow";var u="im_first";var a=["im_drunk","im_baked","im_trippin","im_blown"];var f="mw-strobe_light";var l="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var c="mw_added_css";var w=y();var E=b();var L=document.getElementsByTagName("*"),A=L.length,O,M;var _=null;for(O=0;O<A;O++){M=L[O];if(m(M)){if(S(M)){_=M;break}}}if(M===null){console.warn("Could not find a node of the right size. Please try a different page.");return}h();x();var D=[];for(O=0;O<A;O++){M=L[O];if(m(M)){D.push(M)}}})()
+

以上两种差不多,我个人用的是第二种。具体用法为在 /layouts/partials/extend_head.html 中加入如下代码:

+
<!--  High 一下 --> 
+<div class="pull-right", style="z-index:999">
+<a title="把这个链接拖到你的Chrome收藏夹工具栏中" href='javascript:(function(){function h(){var e=document.createElement("link");e.setAttribute("type","text/css");e.setAttribute("rel","stylesheet");e.setAttribute("href",l);e.setAttribute("class",c);document.body.appendChild(e)}function p(){var e=document.getElementsByClassName(c);for(var t=0;t<e.length;t++){document.body.removeChild(e[t])}}function d(){var e=document.createElement("div");e.setAttribute("class",f);document.body.appendChild(e);setTimeout(function(){document.body.removeChild(e)},100)}function v(e){return{height:e.offsetHeight,width:e.offsetWidth}}function m(i){var s=v(i);return s.height>e&&s.height<n&&s.width>t&&s.width<r}function g(e){var t=e;var n=0;while(!!t){n+=t.offsetTop;t=t.offsetParent}return n}function y(){var e=document.documentElement;if(!!window.innerWidth){return window.innerHeight}else if(e&&!isNaN(e.clientHeight)){return e.clientHeight}return 0}function b(){if(window.pageYOffset){return window.pageYOffset}return Math.max(document.documentElement.scrollTop,document.body.scrollTop)}function S(e){var t=g(e);return t>=E&&t<=w+E}function x(){var e=document.createElement("audio");e.setAttribute("class",c);e.src=i;e.loop=false;var t=false,n=false,r=false;e.addEventListener("timeupdate",function(){var i=e.currentTime,s=D,o=s.length,u;if(i>=.5&&!t){t=true;T(_)}if(i>=15.5&&!n){n=true;k();d();for(u=0;u<o;u++){N(s[u])}}if(e.currentTime>=28.4&&!r){r=true;C()}},true);e.addEventListener("ended",function(){k();p()},true);e.innerHTML="<p>If you are reading this, it is because your browser does not support the audio element. We recommend that you get a new browser.</p>";document.body.appendChild(e);e.play()}function T(e){e.className+=" "+s+" "+u}function N(e){e.className+=" "+s+" "+a[Math.floor(Math.random()*a.length)]}function C(){var e=document.getElementsByClassName(s);for(var t=0;t<e.length;){e[t].className=e[t].className.replace(s,o)}s=o}function k(){var e=document.getElementsByClassName(s);var t=new RegExp("\\b"+s+"\\b");for(var n=0;n<e.length;){e[n].className=e[n].className.replace(t,"")}}var e=30;var t=30;var n=350;var r=350;var i="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake.ogg";var s="mw-harlem_shake_me";var o="mw-harlem_shake_slow";var u="im_first";var a=["im_drunk","im_baked","im_trippin","im_blown"];var f="mw-strobe_light";var l="//s3.amazonaws.com/moovweb-marketing/playground/harlem-shake-style.css";var c="mw_added_css";var w=y();var E=b();var L=document.getElementsByTagName("*"),A=L.length,O,M;var _=null;for(O=0;O<A;O++){M=L[O];if(m(M)){if(S(M)){_=M;break}}}if(M===null){console.warn("Could not find a node of the right size. Please try a different page.");return}h();x();var D=[];for(O=0;O<A;O++){M=L[O];if(m(M)){D.push(M)}}})()'>High一下!</a>
+</div>
+

其中的 href= 的内容替换为上述两种的其中一种即可。

+

修改目录位置到文章页左边

+

根据 sulvblog 的方法来改。

+

修改 toc.html

+

先修改 layouts/partials/toc.html 的代码,替换为:

+
{{- $headers := findRE "<h[1-6].*?>(.|\n])+?</h[1-6]>" .Content -}}
+{{- $has_headers := ge (len $headers) 1 -}}
+{{- if $has_headers -}}
+<aside id="toc-container" class="toc-container wide">
+    <div class="toc">
+        <details {{if (.Param "TocOpen") }} open{{ end }}>
+            <summary accesskey="c" title="(Alt + C)">
+                <span class="details">{{- i18n "toc" | default "Table of Contents" }}</span>
+            </summary>
+
+            <div class="inner">
+                {{- $largest := 6 -}}
+                {{- range $headers -}}
+                {{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
+                {{- $headerLevel := len (seq $headerLevel) -}}
+                {{- if lt $headerLevel $largest -}}
+                {{- $largest = $headerLevel -}}
+                {{- end -}}
+                {{- end -}}
+
+                {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}}
+
+                {{- $.Scratch.Set "bareul" slice -}}
+                <ul>
+                    {{- range seq (sub $firstHeaderLevel $largest) -}}
+                    <ul>
+                        {{- $.Scratch.Add "bareul" (sub (add $largest .) 1) -}}
+                        {{- end -}}
+                        {{- range $i, $header := $headers -}}
+                        {{- $headerLevel := index (findRE "[1-6]" . 1) 0 -}}
+                        {{- $headerLevel := len (seq $headerLevel) -}}
+
+                        {{/* get id="xyz" */}}
+                        {{- $id := index (findRE "(id=\"(.*?)\")" $header 9) 0 }}
+
+                        {{- /* strip id="" to leave xyz, no way to get regex capturing groups in hugo */ -}}
+                        {{- $cleanedID := replace (replace $id "id=\"" "") "\"" "" }}
+                        {{- $header := replaceRE "<h[1-6].*?>((.|\n])+?)</h[1-6]>" "$1" $header -}}
+
+                        {{- if ne $i 0 -}}
+                        {{- $prevHeaderLevel := index (findRE "[1-6]" (index $headers (sub $i 1)) 1) 0 -}}
+                        {{- $prevHeaderLevel := len (seq $prevHeaderLevel) -}}
+                        {{- if gt $headerLevel $prevHeaderLevel -}}
+                        {{- range seq $prevHeaderLevel (sub $headerLevel 1) -}}
+                        <ul>
+                            {{/* the first should not be recorded */}}
+                            {{- if ne $prevHeaderLevel . -}}
+                            {{- $.Scratch.Add "bareul" . -}}
+                            {{- end -}}
+                            {{- end -}}
+                            {{- else -}}
+                            </li>
+                            {{- if lt $headerLevel $prevHeaderLevel -}}
+                            {{- range seq (sub $prevHeaderLevel 1) -1 $headerLevel -}}
+                            {{- if in ($.Scratch.Get "bareul") . -}}
+                        </ul>
+                        {{/* manually do pop item */}}
+                        {{- $tmp := $.Scratch.Get "bareul" -}}
+                        {{- $.Scratch.Delete "bareul" -}}
+                        {{- $.Scratch.Set "bareul" slice}}
+                        {{- range seq (sub (len $tmp) 1) -}}
+                        {{- $.Scratch.Add "bareul" (index $tmp (sub . 1)) -}}
+                        {{- end -}}
+                        {{- else -}}
+                    </ul>
+                    </li>
+                    {{- end -}}
+                    {{- end -}}
+                    {{- end -}}
+                    {{- end }}
+                    <li>
+                        <a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
+                        {{- else }}
+                    <li>
+                        <a href="#{{- $cleanedID -}}" aria-label="{{- $header | plainify -}}">{{- $header | safeHTML -}}</a>
+                        {{- end -}}
+                        {{- end -}}
+                        <!-- {{- $firstHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers 0) 1) 0)) -}} -->
+                        {{- $firstHeaderLevel := $largest }}
+                        {{- $lastHeaderLevel := len (seq (index (findRE "[1-6]" (index $headers (sub (len $headers) 1)) 1) 0)) }}
+                    </li>
+                    {{- range seq (sub $lastHeaderLevel $firstHeaderLevel) -}}
+                    {{- if in ($.Scratch.Get "bareul") (add . $firstHeaderLevel) }}
+                </ul>
+                {{- else }}
+                </ul>
+                </li>
+                {{- end -}}
+                {{- end }}
+                </ul>
+            </div>
+        </details>
+    </div>
+</aside>
+<script>
+    let activeElement;
+    let elements;
+    window.addEventListener('DOMContentLoaded', function (event) {
+        checkTocPosition();
+
+        elements = document.querySelectorAll('h1[id],h2[id],h3[id],h4[id],h5[id],h6[id]');
+         // Make the first header active
+         activeElement = elements[0];
+         const id = encodeURI(activeElement.getAttribute('id')).toLowerCase();
+         document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
+     }, false);
+
+    window.addEventListener('resize', function(event) {
+        checkTocPosition();
+    }, false);
+
+    window.addEventListener('scroll', () => {
+        // Check if there is an object in the top half of the screen or keep the last item active
+        activeElement = Array.from(elements).find((element) => {
+            if ((getOffsetTop(element) - window.pageYOffset) > 0 && 
+                (getOffsetTop(element) - window.pageYOffset) < window.innerHeight/2) {
+                return element;
+            }
+        }) || activeElement
+
+        elements.forEach(element => {
+             const id = encodeURI(element.getAttribute('id')).toLowerCase();
+             if (element === activeElement){
+                 document.querySelector(`.inner ul li a[href="#${id}"]`).classList.add('active');
+             } else {
+                 document.querySelector(`.inner ul li a[href="#${id}"]`).classList.remove('active');
+             }
+         })
+     }, false);
+
+    const main = parseInt(getComputedStyle(document.body).getPropertyValue('--article-width'), 10);
+    const toc = parseInt(getComputedStyle(document.body).getPropertyValue('--toc-width'), 10);
+    const gap = parseInt(getComputedStyle(document.body).getPropertyValue('--gap'), 10);
+
+    function checkTocPosition() {
+        const width = document.body.scrollWidth;
+
+        if (width - main - (toc * 2) - (gap * 4) > 0) {
+            document.getElementById("toc-container").classList.add("wide");
+        } else {
+            document.getElementById("toc-container").classList.remove("wide");
+        }
+    }
+
+    function getOffsetTop(element) {
+        if (!element.getClientRects().length) {
+            return 0;
+        }
+        let rect = element.getBoundingClientRect();
+        let win = element.ownerDocument.defaultView;
+        return rect.top + win.pageYOffset;   
+    }
+</script>
+{{- end }}
+

调用

+

layouts/_default/single.html 文件中默认有 toc.html 的调用,如果未更改的话不用管,更改的话请调用:

+
{{- if (.Param "ShowToc") }}
+{{- partial "toc.html" . }}
+{{- end }}
+

修改 css

+

修改 css/extended/blank.css 文件,加入下方代码:

+
:root {
+    --nav-width: 1380px;
+    --article-width: 650px;
+    --toc-width: 300px;
+}
+
+.toc {
+    margin: 0 2px 40px 2px;
+    border: 1px solid var(--border);
+    background: var(--entry);
+    border-radius: var(--radius);
+    padding: 0.4em;
+}
+
+.toc-container.wide {
+    position: absolute;
+    height: 100%;
+    border-right: 1px solid var(--border);
+    left: calc((var(--toc-width) + var(--gap)) * -1);
+    top: calc(var(--gap) * 2);
+    width: var(--toc-width);
+}
+
+.wide .toc {
+    position: sticky;
+    top: var(--gap);
+    border: unset;
+    background: unset;
+    border-radius: unset;
+    width: 100%;
+    margin: 0 2px 40px 2px;
+}
+
+.toc details summary {
+    cursor: zoom-in;
+    margin-inline-start: 20px;
+    padding: 12px 0;
+}
+
+.toc details[open] summary {
+    font-weight: 500;
+}
+
+.toc-container.wide .toc .inner {
+    margin: 0;
+}
+
+.active {
+    font-size: 110%;
+    font-weight: 600;
+}
+
+.toc ul {
+    list-style-type: circle;
+}
+
+.toc .inner {
+    margin: 0 0 0 20px;
+    padding: 0px 15px 15px 20px;
+    font-size: 16px;
+
+    /*目录显示高度*/
+    max-height: 83vh;
+    overflow-y: auto;
+}
+
+.toc .inner::-webkit-scrollbar-thumb {  /*滚动条*/
+    background: var(--border);
+    border: 7px solid var(--theme);
+    border-radius: var(--radius);
+}
+
+.toc li ul {
+    margin-inline-start: calc(var(--gap) * 0.5);
+    list-style-type: none;
+}
+
+.toc li {
+    list-style: none;
+    font-size: 0.95rem;
+    padding-bottom: 5px;
+}
+
+.toc li a:hover {
+    color: var(--secondary);
+}
+

重新编译后即可看到目录到了左边。

+

修改主题内容宽度

+

修改 ·assets\css\core\theme-vars.css 文件的 :root 节点中的 --main-width 我设置的是 1024px

+

修改代码块

+

修改渲染方式

+

放弃主题默认的 Highlight.js,改为 Hugo 默认的 chroma 方式渲染。根据 官方说明 来改。我用的 style 为 github-dark

+

设置代码块最大高度

+

assets\css\common\post-single.css 文件中找到 .post-content code 增加 max-height: 40em; 。目前设置好最大高度后会与 lineNos: true 设置冲突,会显示两个滑动条 :( ,所以就先不开它。

+

修改文章列表显示的图片位置

+

默认显示的图片在摘要上方而且很大,一页只能显示几个,感觉体验不是很好,所以将它改为在摘要右方显示。我很喜欢 CoolShell 的文章页的显示方法,准备改成差不多样子的。

+

修改 list.html

+

文件为 layouts\_default\list.html 。默认的图片显示代码为:

+
{{- $isHidden := (site.Params.cover.hidden | default site.Params.cover.hiddenInList) }}
+{{- partial "cover.html" (dict "cxt" . "IsHome" true "isHidden" $isHidden) }}
+

位于 <header class="entry-header"> 的上方。将其移动到 <div class="entry-content"> 中并替换默认的 Summary 处理方式,如下所示:

+
<div class="entry-content">
+    {{- $isHidden := (site.Params.cover.hidden | default site.Params.cover.hiddenInList) }}
+    {{- partial "cover.html" (dict "cxt" . "IsHome" true "isHidden" $isHidden) }}
+    {{ .Summary | replaceRE "\n" "<br>" | safeHTML }}{{ if .Truncated }}...{{ end }}
+</div>
+

修改 cover.html

+

文件为 layouts\partials\cover.html 。将 所有 <img 块都加上 align="right" 。完整如下所示:

+
{{- with .cxt}} {{/* Apply proper context from dict */}}
+{{- if (and .Params.cover.image (not $.isHidden)) }}
+{{- $alt := (.Params.cover.alt | default .Params.cover.caption | plainify) }}
+<figure class="entry-cover">
+    {{- $responsiveImages := (.Params.cover.responsiveImages | default site.Params.cover.responsiveImages) | default true }}
+    {{- $addLink := (and site.Params.cover.linkFullImages (not $.IsHome)) }}
+    {{- $pageBundleCover     := (.Resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
+    {{- $globalResourcesCover := (resources.ByType "image").GetMatch (printf "*%s*" (.Params.cover.image)) }}
+    {{- $cover := (or $pageBundleCover $globalResourcesCover)}}
+    {{- if $cover -}}{{/* i.e it is present in page bundle */}}
+        {{- if $addLink }}<a href="{{ (path.Join .RelPermalink .Params.cover.image) | absURL }}" target="_blank"
+            rel="noopener noreferrer">{{ end -}}
+        {{- $sizes := (slice "360" "480" "720" "1080" "1500") }}
+        {{- $processableFormats := (slice "jpg" "jpeg" "png" "tif" "bmp" "gif") -}}
+        {{- if hugo.IsExtended -}}
+            {{- $processableFormats = $processableFormats | append "webp" -}}
+        {{- end -}}
+        {{- $prod := (hugo.IsProduction | or (eq site.Params.env "production")) }}
+        {{- if (and (in $processableFormats $cover.MediaType.SubType) ($responsiveImages) (eq $prod true)) }}
+        <img loading="lazy" align="right" srcset="{{- range $size := $sizes -}}
+                        {{- if (ge $cover.Width $size) -}}
+                        {{ printf "%s %s" (($cover.Resize (printf "%sx" $size)).Permalink) (printf "%sw ," $size) -}}
+                        {{ end }}
+                    {{- end -}}{{$cover.Permalink }} {{printf "%dw" ($cover.Width)}}" 
+            sizes="(min-width: 768px) 720px, 100vw" src="{{ $cover.Permalink }}" alt="{{ $alt }}" 
+            width="{{ $cover.Width }}" height="{{ $cover.Height }}">
+        {{- else }}{{/* Unprocessable image or responsive images disabled */}}
+        <img loading="lazy" align="right" src="{{ (path.Join .RelPermalink .Params.cover.image) | absURL }}" alt="{{ $alt }}">
+        {{- end }}
+    {{- else }}{{/* For absolute urls and external links, no img processing here */}}
+        {{- if $addLink }}<a href="{{ (.Params.cover.image) | absURL }}" target="_blank"
+            rel="noopener noreferrer">{{ end -}}
+            <img loading="lazy" align="right" src="{{ (.Params.cover.image) | absURL }}" alt="{{ $alt }}">
+    {{- end }}
+    {{- if $addLink }}</a>{{ end -}}
+    {{/*  Display Caption  */}}
+    {{- if not $.IsHome }}
+        {{ with .Params.cover.caption }}<p>{{ . | markdownify }}</p>{{- end }}
+    {{- end }}
+</figure>
+{{- end }}{{/* End image */}}
+{{- end -}}{{/* End context */ -}}
+

增加 css

+

在文件 assets\css\extended\blank.css 中增加以下代码:

+
.entry-cover {
+    float:right;
+    width: 20%;
+    margin-left: 20px;
+}
+
+.entry-content {
+    margin: 20px 0;
+    color: var(--secondary);
+    font-size: 14px;
+    line-height: 1.6;
+    overflow: hidden;
+    display: block;
+}
+

这样做完的效果就是文章列表页的摘要可以自由显示文字和图片,默认的 cover 在文字右边,文字会环绕图片显示。

+

标签页词云效果

+

根据 Sulv’s Blog 的方法来改。

+

修改 terms.html

+

layouts/_default/terms.html 中的 <ul class="terms-tags"> 代码块替换为:

+
<ul class="terms-tags">
+    {{- $type := .Type }}
+    {{- range $key, $value := .Data.Terms.Alphabetical }}
+    {{- $name := .Name }}
+    {{- $count := .Count }}
+    {{- with $.Site.GetPage (printf "/%s/%s" $type $name) }}
+    <li>
+        {{ $largestFontSize := 1.5 }}
+        {{ $smallestFontSize := 1 }}
+        {{ $fontSpread := sub $largestFontSize $smallestFontSize }}
+        {{ $max := add (len (index $.Site.Taxonomies.tags.ByCount 0).Pages) 1 }}
+        {{ $min := len (index $.Site.Taxonomies.tags.ByCount.Reverse 0).Pages }}
+        {{ $spread := sub $max $min }}
+        {{ $fontStep := div $fontSpread $spread }}
+        {{ $weigth := div (sub (math.Log $count) (math.Log $min)) (sub (math.Log $max) (math.Log $min)) }}
+        {{ $currentFontSize := (add $smallestFontSize (mul (sub $largestFontSize $smallestFontSize) $weigth)) }}
+        <a href="{{ .Permalink }}" style="font-size: {{ $currentFontSize }}rem; font-weight: {{ mul $currentFontSize 200 }};">
+            {{ .Name }} <sup><strong><sup>{{ $count }}</sup></strong></sup>
+        </a>
+    </li>
+    {{- end }}
+    {{- end }}
+</ul>
+

增加 css

+

assets/css/extended/blank.css 中增加如下代码:

+
/*标签*/
+.terms-tags {
+    text-align: center;
+}
+
+.terms-tags a:hover {
+    background: none;
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.3);
+}
+
+.terms-tags a {
+    border-radius: 30px;
+    background: none;
+    transition: transform 0.5s;
+}
+
+.dark .terms-tags a {
+    background: none;
+}
+
+.dark .terms-tags a:hover {
+    background: none;
+    -moz-transform: scale(1.2);
+    -ms-transform: scale(1.2);
+    -o-transform: scale(1.2);
+    transform: scale(1.3);
+}
+
+.terms-tags li {
+    margin: 5px;
+}
+
]]>
+
+ + + 搭建博客 + https://blog.raikiriww.net/posts/%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2/ + Wed, 18 Oct 2023 22:20:34 +0800 + + https://blog.raikiriww.net/posts/%E6%90%AD%E5%BB%BA%E5%8D%9A%E5%AE%A2/ + <p>使用 Hugo 搭建博客。</p> + 使用 Hugo 搭建博客。

+

安装 Hugo

+

根据 Hugo 官网 的文档来安装 Hugo。

+

安装主题

+

我使用的主题为:hugo-PaperMod ,根据主题文档安装主题(推荐使用 submodule 的方式安装)。将默认的配置文件 hugo.toml 的后缀改为 yaml,方便使用。

+

主题配置

+

复制主题网站给的 Sample config.yml 的内容到 hugo.yaml 中,额外增加:

+
languageCode: zh
+defaultContentLanguage: zh
+

将网站语言设置为中文。

+

默认文章配置

+

复制 Sample Page.md 的内容到 archetypes/default.md 中(title 和 date 不覆盖,只将 toml 格式的配置改为 yaml 格式即可)。可以省去自己一个一个寻找增加的时间,当然,具体内容还是要根据自己的要求来改。

+

写文章

+

使用命令 hugo new content posts/my-first-post.md 来新建一篇文章。

+

本地预览

+

使用命令 hugo server -D 预览生成好的网页。

]]>
+
+ +
+
diff --git "a/tags/\345\215\232\345\256\242\346\220\255\345\273\272/page/1/index.html" "b/tags/\345\215\232\345\256\242\346\220\255\345\273\272/page/1/index.html" new file mode 100644 index 00000000..ab0ff93b --- /dev/null +++ "b/tags/\345\215\232\345\256\242\346\220\255\345\273\272/page/1/index.html" @@ -0,0 +1 @@ +https://blog.raikiriww.net/tags/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/ \ No newline at end of file diff --git "a/tags/\346\212\200\346\234\257/index.html" "b/tags/\346\212\200\346\234\257/index.html" new file mode 100644 index 00000000..9c9168a6 --- /dev/null +++ "b/tags/\346\212\200\346\234\257/index.html" @@ -0,0 +1,5 @@ +技术 | raikiriww's blog
High一下!

Python写入文件失败

公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

...
十月 11, 2023 · 1 分钟 · 143 字 · raikiriww
\ No newline at end of file diff --git "a/tags/\346\212\200\346\234\257/index.xml" "b/tags/\346\212\200\346\234\257/index.xml" new file mode 100644 index 00000000..81b0fbd7 --- /dev/null +++ "b/tags/\346\212\200\346\234\257/index.xml" @@ -0,0 +1,64 @@ + + + + 技术 on raikiriww's blog + https://blog.raikiriww.net/tags/%E6%8A%80%E6%9C%AF/ + Recent content in 技术 on raikiriww's blog + Hugo -- gohugo.io + zh + Wed, 11 Oct 2023 10:29:09 +0800 + + Python写入文件失败 + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + Wed, 11 Oct 2023 10:29:09 +0800 + + https://blog.raikiriww.net/posts/python%E5%86%99%E5%85%A5%E6%96%87%E4%BB%B6%E5%A4%B1%E8%B4%A5/ + <p>公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。</p> + 公司有一个同事做的项目,其中有一个 Python 写的程序会反复降低 CPU 的电压直至死机重启,程序会在降压前保存本次的数据。听起来很合理,先保存数据再降低电压,如果死机了导致重启,那上次的数据也保存到本地了。但在 windows 电脑上实际运行时,每次程序导致 windows 死机重启后,保存的数据文件都为空。他没搞定这个就离职了,于是我就接手来查这个 bug 了。

+

查找问题

+

大概的代码示例如下:

+
# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

从代码结构来看确实没什么问题,是先保存数据再降低电压,即使后边的操作导致死机也是在写入操作完成后,应该不会影响保存的数据才对。但事实是确实有影响,在 windows 上测试了好几次保存的数据都为空。with open() 语句是 Python 中常用的文件操作语句,不应该会导致写入异常,于是怀疑是降压操作导致的。

+

分析问题

+

在 Python 中,当使用 with open() 语句来写入文件时,它会负责管理文件的打开和关闭,通常情况下, with 语句块结束后,Python 会自动关闭文件,并确保所有数据写入硬盘。但,这个操作不是立即发生的。

+

当写入文件时,操作系统通常会缓存这些操作,以便一次性的将多个写入操作合并,从而提高效率。这意味着即使 Python 代码执行了写入操作(也就是 write()),也不能保证这些数据已经永久的保存到了硬盘上。如果在 with 语句块结束后立即死机,这些数据可能会丢失。

+

解决方法

+

现在知道了导致数据保存失败的原因是出在 windows 的系统缓存机制上,那只要找到方法可以强制系统将缓存的数据写入硬盘就好了。修改后的代码如下:

+
# 写入文件
+with open(file_path, "w") as f:
+    f.write(some_data)
+  
+    # 确保数据从 Python 的内部缓冲区写入操作系统的缓冲区
+    f.flush()
+  
+    # 确保数据从操作系统的缓冲区写入磁盘
+    os.fsync(f.fileno())
+logging.warning("Write to checkpoint file")
+
+# 降低 CPU 电压,过低会导致死机
+set_voltage_offset(v_off)
+

新增了两行代码。

+
    +
  • f.flush() 的作用为刷新 Python 的内部缓冲区,确保所有数据写入操作系统的缓冲区。但这个并不能保证操作系统会立刻将数据写入硬盘。
  • +
  • os.fsync(f.fileno()) 的作用为强制操作系统将其缓冲区的数据写入硬盘。这样就保证了如果之后的代码导致系统死机,这部分数据也会完整的保存在硬盘上。
  • +
+

将修改后的程序在 windows 上测试,数据每次都会完整的保存在硬盘上。

+

后记

+

在 Microsoft 的一篇官方文档中有提到 disk write caching ,也就是写入缓存,并给出了关闭的方法。

+

关于 disk write caching ,官方的描述为:

+
+

Additionally, turning disk write caching on may increase operating system performance; however, it may also result in the loss of information if a power failure, equipment failure, or software failure occurs.

+
+

确实与我遇到的情况一样。

+

还有一篇更详细一点的介绍:https://learn.microsoft.com/en-US/windows/client-management/client-tools/change-default-removal-policy-external-storage-media

+

总的来说 disk write caching 在一般情况下可以提高性能。但在需要确保极端情况下写入数据完整性时,可以考虑关闭或者手动强制写入。

]]>
+
+ +
+
diff --git "a/tags/\346\212\200\346\234\257/page/1/index.html" "b/tags/\346\212\200\346\234\257/page/1/index.html" new file mode 100644 index 00000000..a1041534 --- /dev/null +++ "b/tags/\346\212\200\346\234\257/page/1/index.html" @@ -0,0 +1 @@ +https://blog.raikiriww.net/tags/%E6%8A%80%E6%9C%AF/ \ No newline at end of file