如何用浏览器读取本地文件(兼容IE8),new bing能帮我吗?

浏览器读写文件?

有一份老旧而精巧的代码(2006或更早),带js的html,可以只用浏览器来处理一些二进制存档数据。

文件的读写怎么办?通过变通的方法来完成。

利用十六进制编辑软件如WinHEX,直接复制十六进制数值为字符串,贴到一个TextArea以输入;

同样处理过的数据也是生成十六进制字符串,用WinHEX以ASCII Hex的格式粘贴到新文件中。

很巧妙,也有点繁琐,需要人工辅助。

HTML5 FileReader:

最近找到了该程序的汉化版,也是好多年前的了,发现里面设计了直接用<input>来加载文件的功能,用的vbs调用Msxml2.XMLHTTP对象来处理。

可是现在的浏览器基本不支持vbs了,就想改一下,用js来完成。

上网搜索了一堆,XMLHTTP/XMLHttpRequest的代码,有些需要服务器端支持,结果都不理想,或浏览器显示无法创建对象之类的。

刚好new bing的申请也通过了,一番对话式交流,新搜索引擎初试身手,效果不错,直接给出了示例代码。

只要是支持HTML5的现代浏览器,调用FileReader,那叫一个驾轻就熟!

依葫芦画瓢,花了一点功夫也就改造完成了。

这时又回想起一个问题,旧浏览器(IE10以下,原网银的最爱,以下用IE8指代)怎么办。

如何兼容IE8?

有这个必要吗?

都3202年了,不支持HTML5、不支持ES6的浏览器就该回垃圾堆或封存至博物馆!

网银都终于要求兼容Edge啦!

但无聊也是无聊,找了台老电脑远程其桌面,继续随便搜搜“JS读取本地文本文件 IE8兼容”,结果是有一大堆,可大多都是标题党。

在有些参考资料中,提到使用“Microsoft.XMLDOM”对象,试了好久,更适用于文本数据;

FSO对象貌似也只能OpenTextFile或OpenAsTextStream。

以上方法,读取到的是文本字符串数据,都少了很多非可打印/显示字符,当然不行。

还是要用ADODB.Stream,因为它有个方法Read(),可读取二进制数据流。

ADODB.Stream:

碰到两个问题:

  1. 浏览器无法创建对象。安全问题,容易让恶意程序随意读写客户的数据甚至生成木马,所以默认不开放这个功能。这次改改注册表,强行开通玩一下。
  2. 读不到二进制数组。在IE8中调试程序,一到adodb.Read()后面,产生的东西却不是个object,typeof测试一下,unknown...

正想放弃adodb.stream,又搜到一些资料,既然.Read()不行,严肃地建议用.ReadText()方法。

读取文本,用来处理二进制数据,这也行?

行,起码可试。adodb.stream支持对字符集的转换处理,刚好有个神奇的字符集系列:

ISO-8859-1~15

ISO-8859-1(Latin1/Windows-1252),MySQL人士比较熟悉,软件默认的拉丁西欧字符集,它的特点在于对单字节完全编码,1Byte=8bit, 它把所有256个码位全部都排满了。

所以,可用它存储任意二进制数据而不会丢失。

至于编码解码的处理是另外一回事,后续折腾也是由此……

程序好像改造成功,一个数据也没少,不管是否为可打印/显示字符,或者对拉丁来说全是合法字符!

然~~而,读取的数据好像有几个地方有差异!不多、但是不同!

换成变体标准ISO-8859-15差异少了许多,但还是有差异。

十万个为什么?

差异原因

为什么网上的示例代码对二进制形式的图像、声音文件进行复制都没出错,我加载数据到程序中就有差异?

继续追踪调试,找到了端倪,有几个特定的数据,读取出来就变了。

比如84就固定转化为1E80AC……

只是文件复制的话,持续沿用ISO-8859 Latin字符集,同一个管道,怎么In/Out、Read/Write,数据都不会变。

但是一旦用js将数据读取为数值,在转化为16进制字符串时,问题出现了。

因JavaScript引擎内部,所有字符都用 Unicode 表示。而Latin1字符集中的某些符号,在Unicode中是多字节编码。

ISO-8859-15中,这样的字符比较少而已,当然,所处码位也不同。

比如拉丁字符集中用1字节0x80表示了“”,而在Unicode中编码是0x20AC;而“”则由0x84变成了0x201E,等等……

刚好对上!

原二进制数据就这样被转换了,编码冲突,怎么还原?

再问new bing,多次给出的代码也存在这个问题,继续追问Unicode的编码问题,认错态度非常好,但是没有解决方案。

那只能这样了:

手工转换

懒得开笔写代码,new bing也不给我新答案。

刚好又搜索到一位国外友人的代码,问题解决,但是TA用的是CP437字符集,直接把所有256个字符的编码做了个正反对照查询表,转换函数非常之臃肿。

我也不想改用CP437,直接输出了ISO-8859-15中00~FF所有字符经js转换为数值的结果。和原二进制数据相比,也就存在8处不同的Unicode字符嘛,处理过程中查询修正一下就行了。

几行搞定!

还是要自己写……其实也不费力。

示例,读取并显示为HEX

<input type="file" id="fileInput" title="Choose a file" onchange="dispHex(this);"/>
<br />
<h1 id='hexh1'>16进制</h1>
<textarea id='display' title='16进制内容显示' style='width:600px;height:400px;'></textarea>
<script language='javascript' type='text/javascript'>
	function dispHex(f){
		var hexString = "";
		//获取显示框
		var disp = document.getElementById("display");
		if (window.FileReader){
			alert("H5");
			var file = f.files[0];
			var reader = new FileReader();
			//添加读取完成事件
			reader.onload = function(e) {
				var buffer = e.target.result;
				var array = new Uint8Array(buffer);
				for (var i = 0; i < array.length; i++) {
					//将每个元素转化为16进制字符串,并补齐两位,用空格分隔
					var s= '0' + array[i].toString(16);
					s = s.substr(s.length - 2, 2);
					hexString += s;
				}
				//将字符串显示在页面上
				disp.textContent = hexString;
			};
			reader.readAsArrayBuffer(file);
		}
		else if (typeof window.ActiveXObject != 'undefined') {
			alert("IE9及以下,请启用ActiveX控件交互!\n如不能打开文件,请将网页下载至本地运行。\n如何开启Adodb.Stream请自行搜索……");
			var file = f.value;	//网页不在本地,则为fakepath
			//f.select();
			//file = document.selection.createRange().text
			hexString = AdodbReadHexFromFile(file);
			disp.value = hexString;
		}
		else alert("Other!");
	}

	//使用ActiveX,要求浏览器开启相应功能和安全设置,未加错误处理
	function AdodbReadHexFromFile(fileURL){
		var binStr, hexStr="";
		//ADODB方式,需启用:https://www.cnblogs.com/weiweictgu/archive/2007/03/02/661940.html
		var inStream = new ActiveXObject("ADODB.Stream");
			inStream.Type = 2;	//adTypeBinary = 1, 2为Text
			inStream.Open();
			inStream.CharSet = "iso-8859-15";
			//iso-8859-15比iso-8859-1更少收录Unicode中的多字节符号。
			inStream.LoadFromFile(fileURL);
			//.Read()为二进制数组,可结果typeof=unknown.WHY.?.所以用ReadText变通...
			binStr = inStream.ReadText();
			inStream.Close();
			inStream = null;

		//binStr2HEX
		//https://www.codeproject.com/articles/17825/reading-and-writing-binary-files-using-jscript
		var ISO885915=[8364,352,353,381,382,338,339,376];	//单字节集中包含的Unicode字符编码
		var HexOrg=['A4','A6','A8','B4','B8','BC','BD','BE'];	//上述字符Latin0真实16进制值,由比较而来,437/Latin1同理可得
		var isoCheckNum=ISO885915.length;
		for (var i=0 ; i<binStr.length ; i++) {
			var curCode=binStr.charCodeAt(i);
			//charCodeAt可能会解释成多字节,有字符会被错误转换,如'€'
			//因JavaScript引擎内部,所有字符都用 Unicode 表示
			var s,isUnicode=false;
			if(curCode>=256){
				var j;		//IE8不支持indexOf()
				for(j=0;j<isoCheckNum;j++) if(curCode==ISO885915[j]) break;
				if(j<isoCheckNum) isUnicode=true;
			}
			if(isUnicode) s=HexOrg[j];	//查表将Unicode字符转换回正确的单字节16进制
			else{
				s= '0' + curCode.toString(16).toUpperCase();
				//确保是两位数的HEX
				var bytes = 2;
				//var bytes=Math.floor(s.length/2)*2;			//多字节内容处理
				s = s.substr(s.length - bytes, bytes);
			}
			hexStr += s;
		}
		return hexStr;
	}
</script>

后记

ISO-8859之外,还有许多字符集可使用,只要找到冲突编码并转换处理即可;

如果要js动态生成文件供浏览器下载,现代浏览器用blobcreateObjectURL轻松搞定;

在分离FileReader一段代码至子函数时,对异步操作的处理还闹过小问题,Promise的逻辑还真是有些不适合本中老年;

IE8?不想玩了。

奇怪的是,再过了几天,问new bing本文类似的问题,它拒绝给出示例代码,说它不会,说它没有记忆,说IE8没法处理这个读取本地二进制文件的问题……

Post后记

现在我再在Edge Dev中问bing(不限一次对话的回合数了),它直接COPY的就是本文的答案和代码了。

貌似它在认真思考一个字一个词地敲出来,其实就是个动画效果。

原文链接:https://www.cnblogs.com/repus/p/17260978.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:如何用浏览器读取本地文件(兼容IE8),new bing能帮我吗? - Python技术站

(0)
上一篇 2023年4月18日
下一篇 2023年4月18日

相关文章

  • 在Web关闭页面时发送Ajax请求的实现方法

    实现在Web关闭页面时发送Ajax请求,通常需要借助onbeforeunload事件。onbeforeunload事件是一个在页面卸载前触发的事件,在该事件中可以执行一些异步请求的逻辑,实现在页面关闭前的相关操作。 下面是实现在Web关闭页面时发送Ajax请求的步骤: 1.绑定onbeforeunload事件 window.onbeforeunload = …

    JavaScript 2023年6月11日
    00
  • 浅谈JavaScript的内置对象和浏览器对象

    下面我来为你详细讲解“浅谈JavaScript的内置对象和浏览器对象”的完整攻略。 一、JavaScript的内置对象 JavaScript的内置对象包括全局对象、基础(原始)数据类型和引用数据类型。 1. 全局对象 全局对象是指JavaScript中可以在任何地方访问的对象。常见的全局对象有: Math:用于数学计算 Date:用于日期和时间 RegExp…

    JavaScript 2023年5月27日
    00
  • 怎么清空javascript数组

    当我们需要清空一个 JavaScript 数组时,有以下几种方法可以实现。 方法一:重新赋值 可以通过重新将一个空数组赋值给目标数组来清空该数组。代码如下: let arr = [1,2,3,4]; arr = []; console.log(arr); // 输出 [] 在上面的代码中,我们将一个包含 1 到 4 的数组赋给变量 arr,然后使用空数组重新…

    JavaScript 2023年5月27日
    00
  • JavaScript的三种BOM对象

    当我们使用JavaScript编写网页时,页面中除了DOM对象,还有BOM对象,BOM是指浏览器对象模型,它提供了许多与浏览器交互的对象和方法。JavaScript中BOM对象可分为三类:窗口对象、导航对象和屏幕对象。下面就分别来详细讲解这三种BOM对象: 窗口对象 窗口对象是BOM中最常用的对象,它代表整个浏览器窗口或选项卡。窗口对象是通过window对象…

    JavaScript 2023年5月27日
    00
  • 如何利用Three.js实现跳一跳小游戏

    利用Three.js实现跳一跳小游戏的完整攻略如下: 1. Three.js简介 Three.js是一个基于WebGL的JavaScript 3D图形库,可以方便地创建和显示3D场景,是开发WebGL 3D项目的不二选择。在使用Three.js前,需要先了解WebGL和JavaScript。 2. 如何实现跳一跳 2.1 生成游戏场景和跳台 利用Three.…

    JavaScript 2023年6月11日
    00
  • js设置默认时间跨度过程详解

    JavaScript 设置默认时间跨度过程详解 在编写网站或应用程序时,常常需要对一些时间进行处理。如果存在时间跨度选择功能,通常也需要为其提供默认时间跨度。下面将讲解如何使用 JavaScript 设置默认时间跨度。 一、获取当前时间 在设置默认时间跨度之前,我们需要先获取当前时间。可以使用 JavaScript 中的Date对象来获取。 const no…

    JavaScript 2023年5月27日
    00
  • 一个简易的js图片轮播效果

    下面是一个关于实现“一个简易的js图片轮播效果”的完整攻略: 确定需求 首先,我们需要明确实现一个简易的js图片轮播效果的需求。具体来说,它应该具有以下特点: 需要能够自动播放图片; 需要能够通过点击左右箭头手动切换图片,点击小圆点可以快速切换到相应的图片; 图片过渡效果需要流畅自然。 准备html结构 实现一个图片轮播的首要任务就是准备好html结构。我们…

    JavaScript 2023年6月11日
    00
  • js判断样式className同时增加class或删除class

    要判断并增加或删除元素的class,可以使用JavaScript中的classList属性和toggle()方法。classList属性是一个只读的、表示元素类名的集合(DOMTokenList),可以用于添加、删除和切换类名。toggle()方法会在元素中切换一个类名(如果该类名不存在,则添加之;否则删除之)。 以下是增加class的示例: var ele…

    JavaScript 2023年6月10日
    00
合作推广
合作推广
分享本页
返回顶部