是的,你可以(就像我几乎不知道的一些奇怪的人会说的那样)... 是的,你可以通过 ActiveX使用FSO/OpenTextFile使用 Internet Explorer 在 Javascript 中读取和写入二进制文件。事实上,我什至写了一个 Javascript “ Fichier ”(我是法国人)类,它允许 Internet Explorer 以各种模式打开本地文件,包括直接访问模式,提供 Seek(position)、Read(numberOfBytes)、Write(string)和按需保存更改。
例如,它还可以将整个文件加载到字符串中并将其转换为 Base-64:这允许直接从本地磁盘加载图像文件,而不是让它们被某些 Web 服务器上传并随后下载回客户端: 认为从西伦敦到伦敦中心,你必须先从西伦敦到格拉斯哥,然后再从格拉斯哥回到伦敦中心,这真的很奇怪吗?
关键是您只需要知道一个小秘密,否则您将无法将所有字节写入磁盘,也无法将加载的文件转换为 Base-64。考虑到以下两点,我只想告诉你这个秘密:
. 首先,您必须逐字节读取文件,而不是 n>1 的 readAll() 或 read(n)。这样,您可以防止浏览器在某些情况下关联多个字节。因此,您将在内部创建一个带有“objectFile.Read(1)”的循环。
. 其次,这是秘密:在 ASCII+ 表的 256 个字符中(扩展至第 8 位),其中 27 个具有异常行为,这是阻止您操作二进制文件的唯一因素:这 27 个字符位于范围内2个“段落”,即从128到159(80h到9Fh)的32个字节,其中5个除外:129,141,143,144,157:这5个行为正常。但是对于 32 范围内的其他 27 个字节,一旦从磁盘中读取它们,它们就会被更改为 16 位值:例如,欧元符号应该是 UTF- 中的字符 128 (80h) 8,它确实是写入文件中的值。但是在浏览器的内存中,一旦你从磁盘中读取了 80h 字节,它就变成了一个 16 位的值:8364(20ACh)。
要理解这一点,请尝试以下代码,假设您可以在“D:\”目录上写入,否则将代码更改为指定另一个目录,您的浏览器有权在该目录上写入。
<script type="text/javascript'>
fso = new ActiveXObject("Scripting.FileSystemObject");
oFich = fso.OpenTextFile("d:\\foo.txt", 2, true);
var c1 = String.fromCharCode(65); // 65 is the ASCII code for "A"
oFich.write(c1);
oFich.close();
</script>
执行该代码后,您会在磁盘上找到一个“foo.txt”文件:在您的文本板中打开它,您会看到一个完美的“A”。
现在,在上面 Javascript 代码的第 3 行,您可以将值“65”替换为任何其他值,例如“66”将“B”写入 foo.txt 文件,“97”将写入“a”, “55”会写成“7”等等……但是现在,用值“128”试试吧:它变得不愉快,因为你被浏览器侮辱了!像这样:
"Incorrect argument or procedure call"
好吧,您想要的只是将“€”符号写入您的文件中。为什么你不能这样做?因为值 128 不能通过 FSO 写入。上面提到的其他 26 个值也是如此。顺便说一句,不要断定是第 8 位导致该故障,因为 128 是前 8 位数字:如果您将 128 替换为 160 到 255 之间的任何数字,也设置了第 7 位,您'将能够看到它运行良好。
所以,现在试试这个:
fso = new ActiveXObject("Scripting.FileSystemObject");
oFich = fso.OpenTextFile("d:\\foo.txt", 2, true);
var c1 = String.fromCharCode(8364); // 8364 (unicode for "€" symbol ?)
oFich.write(c1);
oFich.close();
您会满意地注意到执行后没有更多的错误消息。然后,输入你的“foo.txt”,你会看到一个漂亮的“€”符号。但令您惊讶的是,如果您将该文件加载到十六进制“转储程序”工具中,您会看到代码不是“AC 20”(8364)而是“80”(128)!
知道了这一点,您现在可以将任何字节字符串转换为 Base-64 或将任何字节字符串写入文件,只要您知道要将“128”字节写入磁盘,除了替换它之外别无他法通过 8364 (20ACh)。顺便说一句,如果你真的想写 8364(20ACh) 没问题:但这意味着你的文件是 16 位值的组合,而不是简单的字节范围。因此,您只需编写结合该数字的两个字节,首先写入低字节:
oFich.write(String.fromCharCode(172)); // 172 = ACh
oFich.write(String.fromCharCode(32)); // 32 = 20h
就您仅操作文本而言,您无事可做:“€”在浏览器的内存和磁盘上的写入方式不同,但它仍然是“€”,因此它是透明的。但是如果你加载字节 128 作为它的数值,那么你会遇到问题,因为你会得到 8364 而不是从文件中读取的每 128 个:这就是为什么很多人在尝试编码时失败的原因Javascript 中的 base-64。
事实上,当你希望它们取数值时,你只需要过滤这 27 个厄运字符。这就是为什么我编写了以下两个函数,我在我的“ Fichier ”类的某些部分使用它们,在需要它们的地方,以及在我的 Base-64 算法中,当我直接从客户端磁盘加载图像文件时,或者当我必须将字节作为数字而不是字符来操作时:
这两个函数抵消了它们 Javascript 模型的部分“变态”:
`String.fromCharcode() and String.charCodeAt()`
因为他们只是简单地封装了他们的模型,所以我给了他们经典的 Basic 名称:“asc”和“chr”,因此它们既易于理解又易于记忆。他们来了:
function asc(c) //(string)->integer
{ // Objet : Renvoie le code ASCII du 1er caractère de la chaine "c"
var i = c.charCodeAt(0);
if (i < 256)
return i; // caractères ordinaires
// (plage 128-159 excepté les 5 caractères 129,141,143,144,157, qui fonctionnent normalement)
switch (i) {
case 8364: // "€"
return 128
case 8218:
return 130
case 402:
return 131
case 8222:
return 132
case 8230:
return 133
case 8224:
return 134
case 8225:
return 135
case 710:
return 136
case 8240:
return 137
case 352:
return 138
case 8249:
return 139
case 338:
return 140
case 381:
return 142
case 8216:
return 145
case 8217:
return 146
case 8220:
return 147
case 8221:
return 148
case 8226:
return 149
case 8211:
return 150
case 8212:
return 151
case 732:
return 152
case 8482:
return 153
case 353:
return 154
case 8250:
return 155
case 339:
return 156
case 382:
return 158
case 376:
return 159
default:
return -1 // provoquera une erreur, le cas ne devant pas se présenter
}
}
function chr(octet) //->(integer)->string
{ // Objet : renvoie le caractère d'un nombre 8 bits
// Entrée : "octet" est un nombre 8 bits non signé (entre 0 et 255)
// Sortie : le caractère correspondant est renvoyé, les codes échappés sont rattrapés par un switch
if (octet < 128) || (octet > 159))
return String.fromCharCode(octet); // caractères ordinaires, traités par String.fromCharCode
switch (octet) {
case 128:
return "€"
case 129:
return String.fromCharCode(129);
case 130:
return "‚"
case 131:
return "ƒ"
case 132:
return "„"
case 133:
return "…"
case 134:
return "†"
case 135:
return "‡"
case 136:
return "ˆ"
case 137:
return "‰"
case 138:
return "Š"
case 139:
return "‹"
case 140:
return "Œ"
case 141:
return String.fromCharCode(141);
case 142:
return "Ž"
case 143:
return String.fromCharCode(143);
case 144:
return String.fromCharCode(144);
case 145:
return "‘"
case 146:
return "’"
case 147:
return "“"
case 148:
return "”"
case 149:
return "•"
case 150:
return "–"
case 151:
return "—"
case 152:
return "˜"
case 153:
return "™"
case 154:
return "š"
case 155:
return "›"
case 156:
return "œ"
case 157:
return String.fromCharCode(157);
case 158:
return "ž"
case 159:
return "Ÿ"
default:
return String.fromCharCode(octet); // unicode 16 bits
}
}
现在,您可以使用 ActiveX 在您允许 IE 访问文件的磁盘的每个区域上使用 Internet Explorer 二进制读取和写入任何类型的文件。
正如伟大而怀念的法国幽默家 Pierre Desproges 曾经说过的那样:“ Etonnant,非? ”
BB。