#javascript
#javascript
Вопрос:
Я пытаюсь заставить скрипт работать, который называетсяsfo.js.
В репозитории упоминается только это использование:
keys = parse_sfo(Some_ArrayBuffer);
console.log(keys['TITLE']);
Просматривая sfo.js
, parse_sfo
имеет sfoBytes
аргумент.
Из этого я пришел к выводу, что sfoBytes
аргументом должен быть массив байтов файла.
Я попытался создать скрипт, который преобразует файл SFO в массив байтов:
<script src="sfo.js"></script>
<script>
function stringToArrayBuffer(str) {
var buf = [];
for (var i=0, strLen=str.length; i<strLen; i ) {
buf[i] = str.charCodeAt(i);
}
console.log(buf);
return buf;
}
function testing(url) {
var request = new XMLHttpRequest();
request.open('GET', url, false);
request.send(null);
if (request.status === 200) {
console.log(request.response);
var response = request.response;
var array = stringToArrayBuffer(response);
return array;
} else {
alert('Error!');
}
}
var data = testing('param.sfo');
var sfo = parse_sfo(data);
</script>
Это выдает ошибку в консоли:
Uncaught RangeError: byte length of Uint32Array should be a multiple of 4 at new Uint32Array (<anonymous>)
at readUint32At (sfo.js:20)
at parse_sfo (sfo.js:113)
at (index):29
Я почти уверен, что делаю что-то не так. Кто-нибудь понимает, как я могу заставить скрипт работать должным образом?
У меня есть пример файла для param.sfo: https://filebin.net/gghosrp6u93jn7y8 (если ссылка на загрузку запрещена, пожалуйста, дайте мне знать)
Комментарии:
1. Что вы хотите — заставить скрипт
sfo
работать, или вам нужно преобразовать файл в массив байт?2. Я имею в виду, например, у вас есть URL файла в качестве входных данных, и вы хотите
Uint8Array
в качестве выходных данных?3. @Anton Я не уверен, что делать, чтобы sfo.js скрипт работает. Я задаю этот вопрос, чтобы выяснить, как я могу заставить скрипт работать.
4. Ссылка, которую вы предоставили в качестве примера для ‘param.fso’, представляет собой изображение. На самом деле
mathjax_post.JPG
. Может быть, я делаю что-то не так? Но, похоже, что этот JPG не является файлом FSO.5. Нет проблем, я сам нашел param.sfo.
Ответ №1:
Хорошо, наконец, рабочий пример.
Я нашел небольшой файл param.sfo в Интернете.
Примечания:
- существует 2 версии программы чтения файлов: локальная и удаленная
- в приведенном ниже фрагменте вы можете протестировать оба (я добавил свой param.sfo в качестве внешней ссылки для тестирования ‘remote’). Для тестирования ‘local’ вам просто нужно выбрать любой файл sfo на вашем компьютере.
- в результате я показываю все ключи, а не только ‘TITLE’ (как в вашем вопросе). Затем вы можете выбрать желаемый ключ
function getSfoLocal(callback) {
// for now I use local file for testing
document.querySelector('input').addEventListener('change', function() {
var reader = new FileReader();
reader.onload = function() {
var arrayBuffer = this.result;
var array = new Uint8Array(arrayBuffer);
// var binaryString = String.fromCharCode.apply(null, array);
if (typeof callback === 'function') callback(array);
}
reader.readAsArrayBuffer(this.files[0]);
}, false);
}
function getSfoRemote(url, callback) {
var concatArrayBuffers = function(buffer1, buffer2) {
if (!buffer1) {
return buffer2;
} else if (!buffer2) {
return buffer1;
}
var tmp = new Uint8Array(buffer1.length buffer2.length);
tmp.set(buffer1, 0);
tmp.set(buffer2, buffer1.byteLength);
return tmp.buffer;
};
fetch(url).then(res => {
const reader = res.body.getReader();
let charsReceived = 0;
let result = new Uint8Array;
reader.read().then(function processText({
done,
value
}) {
// Result objects contain two properties:
// done - true if the stream has already given you all its data.
// value - some data. Always undefined when done is true.
if (done) {
if (typeof callback === 'function') callback(result);
return resu<
}
// value for fetch streams is a Uint8Array
charsReceived = value.length;
const chunk = value;
result = concatArrayBuffers(result, chunk);
// Read some more, and call this function again
return reader.read().then(processText);
});
});
}
function getSfo(type, url, callback) {
if (type === 'local') getSfoLocal(callback);
if (type === 'remote') getSfoRemote(url, callback);
}
getSfo('local', null, (data) => {
keys = parse_sfo(data);
console.log('LOCAL =', keys);
});
function goremote() {
getSfo('remote', 'https://srv-file9.gofile.io/download/Y0gVfw/PARAM.SFO', (data) => {
keys = parse_sfo(data);
console.log('REMOTE =', keys);
});
}
div { padding: 4px; }
<!--script src="https://rawcdn.githack.com/KuromeSan/sfo.js/c7aa8209785cc5a39c4231e683f6a2d1b1e91153/sfo.js" for="release"></script-->
<script src="https://raw.githack.com/KuromeSan/sfo.js/master/sfo.js" for="develop"></script>
<div>Local version: <input type="file" /></div>
<div>Remote version: <button onclick="goremote()">Go remote</button></div>
P.S. Кажется, что gofile.io
сервис, который я использовал для удаленного примера, иногда не виден. Если у вас есть постоянная ссылка на param.sfo, просто дайте мне знать. Но теперь я должен зайти в свой файл, и только после этого он становится видимым.
Комментарии:
1. Привет, Антон, это действительно отлично работает! Большое спасибо.
Ответ №2:
Вы используете JavaScript 20-летней давности. Пожалуйста, используйте fetch add TextEncoder для вашего собственного здравомыслия.
fetch(url).then(res => res.json().then(data => {
const encoder = new TextEncoder()
const bytes = encoder.encode(data)
parse_sfo(data)
})
Комментарии:
1. Спасибо за ответ Konowy. К сожалению, код выдает ошибку «Uncaught (in promise) SyntaxError: неожиданный токен», я отредактировал вопрос с исправленным фрагментом
2. Я удалил бит JSON, затем он говорит «Недопустимый SFO»
Ответ №3:
sfoBytes должен быть фактическим буфером массива файла sfo. Это проще, чем то, что вы пытаетесь, вам не нужно преобразовывать ответ на запрос с помощью stringToArrayBuffer, поскольку вы можете получить буфер массива из XMLHttpRequest. Кроме того, файл SFO не является текстовым файлом, он двоичный, поэтому преобразование из строки все равно не сработало бы.
Изменение вашего запроса для получения типа ответа arraybuffer должно выполняться следующим образом:
function testing(url) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = "arraybuffer";
request.send(null);
if (request.status === 200) {
console.log(request.response);
var response = request.response;
var sfo = parse_sfo(response);
} else {
alert('Error!');
}
}
Комментарии:
1. Большое спасибо за ваш ответ, Жюльен. Я пробовал ваш пример, но я получаю
(index):5 [Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/. testing @ (index):5 (anonymous) @ (index):19 (index):6 Uncaught DOMException: Failed to set the 'responseType' property on 'XMLHttpRequest': The response type cannot be changed for synchronous requests made from a document.
2. О, я не заметил, что запрос xmlhttprequest был синхронным, я отредактировал ответ. Просто измените request.open(‘GET’, url, false) на request.open(‘GET’, url, true)
3. Спасибо за ответ. Кажется, что
request.status
всегда равно 0, я сделалconsole.log(request.status);
сразу после отправки. Вызываемая функция выглядит следующим образом:testing('param.sfo');
иparam.sfo
находится в той же папке