其实对于目前的形式来说,虽然像 U 盘、固态硬盘、甚至光盘这些信息储存介质(设备)的容量越来越高,但是不得不说这些设备的可靠性依然像悬着的一块石头,虽然这块石头确实牢牢的粘在天花板上,但是毕竟是粘上去的,总有可能会突然掉下来。

随着现在各种数码信息生成应用的广泛普及,我们每天都会产生大量的数据,以至于我们时常忽视了信息备份的必要性。现在手机内部存储 200 多 GB ,但是依然很快就能被占满,比电脑还要容易占满,很难想象在未来,如果这些海量的数据因为设备的不可靠性而丢失,那将是一个多么可惜的事情?

不是任何数据都值得备份,相比于备份所有数据,备份数据之中的重点等则是很重要的。可能就是其中自己喜欢的照片,然而将它放在手机中,甚至云盘上都不能称之为可靠,手机会坏,比如我之前使用的手机 huawei nove 2s,在我换了新手机后,因为同学的手机被老师没收了我便借给他,但是因为他玩心很大,嘻嘻哈哈中将衣服和我的手机同时甩入天空,然后手机粉身碎骨,其内部数据虽然部分有备份,但终究是损失了很多,尤其是大量的珍贵照片。云盘也不可靠,在七八年前,那时设备很简单,家里有废旧手机若干、几个 GB 的简单内存卡数张、还有一个慢如黄牛的电脑一台,它们带着我走过了很多年,储存了我很多的数据,当然最重要的是那些珍贵的照片。于是我就全存储到了 360 云盘上,因为存储介质在当时及其昂贵,一个蔫蔫数 GB 的内存卡就是好几天的饭钱,所以我几乎没有其他的备份,电脑的硬盘也好像很容易坏,总之我的数据没有备份,但是我未曾想到的是,360 云盘居然嗝屁了。。。然后那些过去的回忆,全都毁于一旦。虽然那时有抢救下载服务,但是终归错过了。

所以我很想找到一个比较可靠的储存方式。我看到了 A4 纸,家里有打印机,也有一个坏掉的喷墨打印机可作为一个扫描仪。于是就想使用打印的方式使用一定方式将二进制数据打印到纸上,进而实现数据的备份,毕竟肉眼可看到数据的细节,心里会很安心。去年末我曾经找到一个叫 PaperBack的软件来使用该方式打印到纸上,然后使用扫描仪就能还原数据,但是因为需要打印机与扫描仪共同配合使用,所以始终没有完整尝试过。于是想自制一个。

最开始我想到了 vscode 的 hex editor 插件,可以编辑二进制文件,但是由于自己缺乏相关知识,所以无法从得知二进制数据然后制作二进制文件,然后我想到了基于二进制的 base64 ,然后就自制了两个测试网页。

复制图片就能转为 base64 源码:https://www.ccgxk.com/123.html

base64 与文件互转工具:https://www.ccgxk.com/124.html

因为 base64 不仅可以将图片转换为 ASCII 码,而且也能将任何文件转化,并且还能反向进行还原成文件下载。所以问题就简化成在纸上以适当方式转化为一串长长的 ASCII 码。

然而如何能识别纸上的呢?我想到了 github 的南极源代码那个计划,他们使用的 QR 码刻在胶卷上来记录信息,我或许也可以如此?但是在网上找了很久也没找到他们行动的细节,他们报道里的 QR 码是指的日本那个传统上的 QR 码还是通指的 QR 码呢?我不知道。不过在我的测试下,发现 QR 码是为方便扫描而生的,对于简单的数据会产生很巨大的图像,因此并不适用于我的计划。虽然还做了个页面吧。能生成复杂程度级别最低的 QR 码,https://www.ccgxk.com/125.html ,如果用 QR 码来记录信息,那数据量将难以想象。

于是又尝试自己研究识别图像的方式,我知道有个 openvc 库,专门专注于图片领域,但是吧,不会,自己就研究吧,就弄了个,做了一半才知道这个还是有点难度的。

源码在此处,感兴趣的小伙伴可以自己尝试一番

点击查看代码
<style>
* {
box-sizing: border-box
}
table {
border: red 1px solid;
}
td {
padding: 0;
border: 0;
width: 3px;
height: 3px;
}
.the_black{
background: black;
}
</style> <body>
<p class="image">
<img src="./img08.png" width="100px" id="img" />
</p>
<input type="number" value="230" id="blackThreshold" />
<button onclick="drawTableImg()">点击转换</button>
<canvas id="myCanvas" width="250" style="display: none;"></canvas>
<div id="tableDiv"></div>
<body> <script>
const dom = document.getElementById("myCanvas"); // canvas画布
let colorData = new Array;
let canvasWidth = dom.width; // 获取 canvas 元素上的宽度,以在转 2 维数组时作为分行依据
let imgDom = document.getElementById("img"); function drawTableImg(){
let threshold = document.getElementById("blackThreshold").value; // 获取黑色阈值(0~255)
getImageData(dom, imgDom.src).then((data)=>{
let colorData = data;
let colorData2d = dataTo2d(colorData, canvasWidth, threshold); // 一维转单色、二维
// 绘制
outTable(colorData2d);
})
} /**
* 获取图片源像素信息
*/
function getImageData(dom, url){
const ctx = dom.getContext("2d"); // 设置在画布上绘图的环境
const image = new Image();
image.src = url; let imgH = document.getElementById("img").height;
dom.height = dom.width * (imgH/100);
//获取画布宽高
const w = dom.width;
const h = dom.height ;
return new Promise((resolve)=>{
image.onload = function(){
ctx.drawImage(image, 0, 0 ,w,h); // 将图片绘制到画布上
const imgData = ctx.getImageData(0,0,w,h); // 获取画布上的图像像素
resolve(imgData.data) // 获取到的数据为一维数组,包含图像的 RGBA四个通道数据
ctx.clearRect(0,0,w,h);
}
})
} /**
* 把颜色数组改成一维数组
*/
function getColor(array, threshold){
let result = new Array();
let nCutTimes = array.length / 4;
for (let index = 0; index < nCutTimes; index++) {
let key = array[index * 4];
result[index] = (key > threshold) ? 0 : 1;
}
return result;
} /**
* 改成二维数组(图片平铺)
* @param array 数组(颜色数据)
* @param width 图宽(宽度像素值)
*/
function to2dArray(array, width){
let arrLen = array.length;
let result = new Array();
result[0] = new Array(); // 初始化第一行 for (let index = 0,key = 0,line = 0; index < arrLen; index++) {
out("index" + index + " key" + key + " line" + line);
result[line][key] = array[index];
if(key === (width - 1)){ // 如果到每一行的最后一个元素了,就另起一行(申请新数组,行号变量加一,key 清零)
line++;
if(width * (line+1) > arrLen) break; // 如果新的一行大于图像的高度,则退出循环
result[line] = new Array();
key = 0;
}else{
key++
}
}
return result;
} /**
* 渲染输出成黑白表格
*/
function outTable(array2d){
out(array2d);
let outTableData = `<table>`;
for(let i = 0 ; i < array2d.length; i++){
outTableData += `</tr>`;
for(let j = 0 ; j < array2d[i].length; j++){
if(array2d[i][j] == 1){
outTableData += `<td class="the_black"></td>`;
}else{
outTableData += `<td></td>`;
} }
outTableData += `</tr>`;
}
outTableData += `</table>`; // 渲染完毕 document.getElementById("tableDiv").innerHTML = outTableData; // 输出
} /**
* 将图片源代码数据转化为二维数组
*/
function dataTo2d(array, width, threshold){
array = getColor(array, threshold);
array = to2dArray(array, width);
return array;
}

最终因为时间不足,暂时放弃了。

我躺着床上,思考有没有其他可靠的方式了?想到了七牛云的冷储存,突然灵光一现,果然还是要放云上。虽然光盘之前也考虑过,但是据说其寿命其实很短,不算可靠,那还是使用云上的吧。

七牛云有深度归档储存服务,用来储存冷数据的,看了一下可靠性,99.999...99%(11 个 9),算了,就用这个吧,再怎么说这个是专业搞企业级数据储存的,有很多超大公司都在用他们保存重要的档案数据,我也就用吧,一个月一个 GB 才 1 分钱,一碗凉皮就够我一年存 50 GB 的数据了。只是深度冷储存有条件,就是解冻需要 5 到多少多少小时,不过听起来不仅觉得不会不方便,反而觉得有点可靠,这可能就真有那种冰封解冻的感觉。(不过实际上可能是储存在数据磁带里)

现在我在我之前的七牛云里又加了个仓库,专门存冷数据的,以后把相机等或者整理整理的东西都存进去。也很像一个时光胶囊,因为启封一次需要耗费很久,所以这些数据们存到仓库里,就等于很久后才会重见天日。

虽然七牛云很可靠,但也不排除它会跑掉或者不可抗力消失,所以对于使用 A4 纸去储存数据的研究以后有空还会继续。

寻找可靠的长久的存储介质之旅,以及背后制作的三个网页“图片粘贴转base64”、“生成L纠错级别的QR码”、“上传文件转 base64以及粘贴 base64 转可下载文件”的更多相关文章

  1. php ini_set更改php.ini配置,通过它修改php.in达到php上传文件大小限制是不行的,除非修改.htaccess文件

    PHP ini_set() 无效的原因:如题:我租的是虚拟主机,php.ini里的upload_max_filesize是默认的2M,要直接修改php.ini文件是不可能的.我如果想上传超过2M的怎么 ...

  2. Mac 上 Apache Apollo 的安装与运行,和官方下载文件中 Python 实例的演示

    前不久我在 Mac 上成功安装了 mosquitto,这次我又试了试安装另一个热门的 broker —— Apache Apollo.对在 Mac 上安装 mosquitto 感兴趣的可以点击查看我的 ...

  3. ajaxsubmit 上传文件 在IE中返回的内容 提示下载文件

    在ajaxSubmit提交表单的时候,如果表单内有文件上传的话,会判断参数是否配置的iframe为false参数,如果没有,会用创建隐藏iframe方式提交表单,如果设定了iframe为false,则 ...

  4. Html5实现头像上传和编辑,保存为Base64的图片过程

    一.Html5实现头像上传和编辑 插件地址: html5手机端裁剪图片上传头像代码 本地项目引入注意事项: 1.将html的js搬到外面的js文件中,便于管理 2.图片样式在html都是在页面写死,需 ...

  5. 前端图片转base64,转格式,转blob,上传的总结

    1. 图片文件转base64 <input accept="image/gif,image/jpeg,image/jpg,image/png" type="file ...

  6. npm包的上传npm包的步骤,与更新和下载步骤

    官网: ======================================================= 没有账号可以先注册一个,右上角点击“Sign Up",有账号直接点击“ ...

  7. EasyNVR摄像机网页Chrome无插件视频播放功能二次开发之通道配置文件上传下载示例代码

    背景需求 熟悉EasyNVR产品的朋友们都知道,产品设计初期根据整个直播流程层级,我们将EasyNVR无插件直播系统划分为:硬件层.能力层.应用层,连接硬件与应用之间的桥梁,同时屏蔽各种厂家硬件的不同 ...

  8. 模拟文件上传(二):使用apache fileupload组件进行文件上传

    其中涉及到的jar包: jsp显示层: <%@ page language="java" import="java.util.*" pageEncodin ...

  9. Kindeditor富文本实现textarea文本域的上传及单独button 按钮绑定(用来实现单文件上传)

    在最近项目要新增一个内容文章,文章包含一般的正文内容,其中正文中可以包含多张图片.文章最多包含一个音频文件.文章正文的上传功能我是通过textarea文本域绑定kindeditor编辑器实现的,而单独 ...

  10. js实现图片上传预览功能,使用base64编码来实现

    实现图片上传的方法有很多,这里我们介绍比较简单的一种,使用base64对图片信息进行编码,然后直接将图片的base64信息存到数据库. 但是对于系统中需要上传的图片较多时并不建议采用这种方式,我们一般 ...

随机推荐

  1. 阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践

    本文由阿里闲鱼技术团队景松分享,原题"到达率99.9%:闲鱼消息在高速上换引擎(集大成)",有修订和改动,感谢作者的分享. 1.引言 在2020年年初的时候接手了闲鱼的IM即时消息 ...

  2. C++书籍推荐

    本人收藏的一些电子版: 阅读顺序 C++ primer 基础 Professional C++ 基础+新特性 现代C++语言核心特性解析 更多新特性,STL并发库介绍 C++ Templates 更多 ...

  3. 小程序IOS系统input设置maxlength时,输入到最后如果输入汉字的拼音长度超过限制会直接中断输入(bug bug)

    我的解决办法:不在输入框限制长度,在提交表单的时候判断长度,欢迎大家有好的解决方法分享一下

  4. 优化永不止步:TinyVue v3.20.0 正式发布,更美观的官网UI,更友好的文档搜索,更强大的主题配置能力~

    你好,我是 Kagol,个人公众号:前端开源星球. 我们非常高兴地宣布,2024年12月4日,TinyVue 发布了 v3.20.0 . 本次 3.20.0 版本主要有以下重大变更: OpenTiny ...

  5. python SQLAlchemy ORM——从零开始学习03 如何针对数据库信息进行排序

    03 如何进行排序 3-1准备工作: 因为要排序,所以需要随机多谢数据,model见后文.也需要random进行随机 from model import User, Engine from sqlal ...

  6. Linux curl brew命令详解

    命令:curl 在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具.它支持文件的上传和下载,是综合传输工具,但按传统,习惯称url为下载工具 ...

  7. biancheng-JSTL标签库

    JSP 标签是一组与 HTML 标签相似,但又比 HTML 标签强大的功能标签.JSTL 用来简化 JSP 开发,可以使我们不用嵌入 Java 代码就能够开发出复杂的 JSP 页面.JSTL 包含 5 ...

  8. canal源码分析简介-1

    1.0 canal源码分析简介 canal是阿里巴巴开源的mysql数据库binlog的增量订阅&消费组件.项目github地址为:https://github.com/alibaba/can ...

  9. jdk 5.0 新增的foreach循环(用于遍历集合、数组)

    使用 foreach 循环遍历集合元素 Java 5.0 提供了 foreach 循环迭代访问 Collection和数组. 遍历操作不需获取Collection或数组的长度,无需使用索引访问元素 ...

  10. String、StringBuffer、StringBuilder三者的异同

    /*String.StringBuffer.StringBuilder三者的异同?String:不可变的字符序列:底层使用char[]存储StringBuffer:可变的字符序列:线程安全的,效率低: ...