«

寻找可靠的长久的存储介质之旅,以及背后制作的三个网页

时间:2022-7-9 07:44     作者:独元殇     分类: 前端技术


其实对于目前的形式来说,虽然像 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 库,专门专注于图片领域,但是吧,不会,自己就研究吧,就弄了个,做了一半才知道这个还是有点难度的。

image

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

<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 纸去储存数据的研究以后有空还会继续。

标签: 原创 JS QR 七牛云

推荐阅读: