Предполагается, что следующий код импортирует данные в localStorage из файла CSV. Цель состоит в том, чтобы заменить/обновить любые существующие данные localStorage. Я использую FileReader для импорта и пытаюсь использовать JSON.stringify, чтобы сохранить его в localStorage.
const fileInput = document.getElementById('csv');
const readFile = () => {
const reader = new FileReader();
reader.onload = () => {
localStorage.setItem("entry_list", JSON.stringify(reader.result));
}
reader.readAsArrayBuffer(fileInput.files[0]);
};
fileInput.addEventListener('change', readFile);
Я считаю, что проблема в том, что он пытается импортировать это как ОБЪЕКТ, а не МАССИВ. Как мне подойти к этой проблеме или решить эту проблему?
ОБНОВЛЯТЬ: Благодаря ответу, опубликованному zzzggghhh ниже, мне удалось решить эту проблему на 90%. Единственная оставшаяся проблема заключается в том, что один из элементов массива, который является числом, должен быть числом с плавающей запятой. Таким образом, метод разделения должен каким-то образом учитывать это. Возможно ли это вообще?
Вот что импортируется:
Мне нужно, чтобы его импортировали следующим образом (без кавычек в плавающей запятой):
Вот для этого я и прошу помощи. При импорте данные импортируются неправильно. Кажется, что из импорта CSV создается ОБЪЕКТ вместо МАССИВА. Кроме того, он не передает никаких данных. В файле CSV есть данные, но они не импортируются.
Проблема в том, что вы пытаетесь использовать JSON.stringify
на объекте ArrayBuffer
. ArrayBuffer
не имеет перечислимых свойств объекта и, следовательно, становится просто {}
при строковом преобразовании.
Либо превратите его в обычный массив, используя JSON.stringify(Array.from(new Uint8Array(reader.result)))
, чтобы получить каждый байт в файле как число, либо — моя рекомендация, поскольку его легче снова превратить в файл и хранить меньшего размера — не читайте его как ArrayBuffer
в первом поместите, а как URI данных (который будет использовать кодировку Base64), заменив readAsArrayBuffer
на readAsDataURL
.
Однако, основываясь на ваших комментариях, я теперь совершенно уверен, что вы хотели бы также проанализировать содержимое CSV, а не просто сохранить файл. В этом случае взгляните на один из многочисленных пакетов анализа CSV, например csv-parse.
Вот пример того, как его использовать:
const fileInput = document.getElementById('csv');
const readFile = () => {
const reader = new FileReader();
reader.onload = () => {
const csvData = csv_parse_sync.parse(reader.result, { columns: true });
// Commented out because sandboxed demo cannot access localStorage
//localStorage.setItem("entry_list", JSON.stringify(csvData));
// For demo purposes, show would normally get stored
document.getElementById('output').innerText = JSON.stringify(csvData);
}
reader.readAsText(fileInput.files[0]);
};
fileInput.addEventListener('change', readFile);
<script src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/sync.min.js"></script>
<input type = "file" id = "csv">
<pre id = "output"></pre>
Вместо CDN, который я использовал здесь, вы обычно копируете соответствующий файл из пакета на свой сервер (или устанавливаете пакет там, если можете) и ссылаетесь на файл таким образом.
Да, надеюсь, я не перепутал. Я не хочу хранить его в виде файла. У меня уже есть данные в файле CSV. Та часть моего кода, которая здесь не показана, работает отлично. Мне нужно прочитать данные в CSV и поместить в localStorage (обновить/заменить) то, что уже есть. Я надеюсь в этом есть смысл. Спасибо
Да, но каким образом? CSV-файл содержит только байты. Вам решать, как их интерпретировать. Я предполагаю, что вы хотите проанализировать CSV в массив объектов на основе имен столбцов, и в этом вам могут помочь такие пакеты, как csv-parse
, но вы этого не сказали. С таким же успехом вы можете хранить массив массивов ячеек или просто текст, анализируемый в какой-либо кодировке, например UTF-8. (Или необработанные байты, как я изначально думал.)
Хорошо, я должен признать, я новичок, поэтому, возможно, я не совсем знаю, «что сказать». В настоящее время у меня есть массив объектов в локальном хранилище. Все, что я хочу сделать, это заменить или обновить эти данные данными, хранящимися в CSV. Я последую вашему совету и поищу дополнительную информацию о синтаксическом анализе csv, хотя он предназначен для Node.JS, который я не использую. Нет ли подхода с использованием ванильного JS?
Не уверен, что это поможет, но я попробовал это: localStorage.setItem("entry_list", JSON.stringify(Array.from(reader.result))); но массив по-прежнему пуст в localStorage, но ошибок нет
Нет, csv-parse
также для браузера. Цитирую страницу, на которую я дал ссылку: Multiple distributions: Node.js, Web, ECMAScript modules and CommonJS
. Все это объяснено на их сайте.
Кроме того, что касается того, что вы пробовали в последний раз, это тоже не может сработать, потому что вы забыли промежуточное преобразование в new Uint8Array
, как я показал в своем ответе выше. Но теперь я совершенно уверен, что исходное содержимое файла вам все равно не понадобится.
Первый шаг в инструкциях по синтаксическому анализу csv: Запустите npm install csv, чтобы установить полный модуль CSV, или запустите npm install csv-parse, если вас интересует только синтаксический анализатор CSV. У меня нет Node.JS, и это должно быть решение на стороне клиента. Я ценю эту помощь, но мне нужен практический пример. Думаю, мне нужно нанять кого-нибудь, чтобы помочь мне найти решение. Я действительно не думал, что получить практический пример или демо-версию от этого сообщества так сложно. Я, очевидно, иду по пути, который выходит за рамки моих навыков. Спасибо...
Обычно ваш интерфейс в настоящее время также использует узел для сборки. В конце вы получаете только код на стороне клиента, но процесс сборки использует пакеты узлов, поэтому в первом объяснении используется npm, но вам не обязательно идти по этому пути. Вы также можете использовать предоставленный браузерный дистрибутив IIFE, на веб-сайте это также показано в качестве примера. Я собираюсь добавить это более подробно в свой ответ, теперь, когда я совершенно уверен, что понимаю, что вам нужно.
Я добавил конкретный пример.
CSV представляет собой открытый текст, импорт буфера массива предназначен для двоичных данных/файлов. Вы можете просто использовать API-интерфейс выборки, чтобы прочитать весь текст, а затем проанализировать его на объекты из CSV, возможно, с помощью модуля:
const fileInput = document.getElementById('csv')
const update = async () => {
const [header, ... rows] = (await fileInput.files[0].text()).trim().split(/[\r\n]+/).map(line => line.split(','))
const records = rows.map(row => row.reduce((record, field, i) => Object.assign(record, {[header[i]]: field}), {}))
localStorage.setItem("entry_list", JSON.stringify(records))
}
fileInput.addEventListener('change', update)
Это неправильно анализирует файл CSV. (И нет, разделения запятыми тоже будет недостаточно, потому что вы можете иметь поля в кавычках, вы также можете иметь поля в кавычках, охватывающие несколько строк, и вы можете экранировать кавычки внутри полей в кавычках.) - Вот почему я предложил использовать существующая библиотека для этого.
Ваш тоже, ему решать, какой сторонний пакет CSV он хочет использовать.
Мой даже не пытается, так как знаю, что это было бы неправильно. Но ваш ответ идет на полпути, и он идет в неправильном направлении. Также вы не можете fetch
объект File
. Попробуйте сами.
Вы действительно можете получить файл.
Посмотрите сами: jsfiddle.net/ytcksnbL — вы получаете некоторый HTML-мусор, потому что в конечном итоге получаете страницу 404, пытаясь получить данные из URL-адреса [object%20File]
.
Круто, он не опубликовал HTML, поэтому я предположил, что это код сервера Node.
Спасибо, zzzggghhh, это очень близко приближает меня к успеху. Я думаю, что узнаю, что здесь происходит. Кажется, есть одна небольшая проблема: если у меня возникают проблемы, я думаю, что это связано с тем, как они разбиваются, и выходные данные должны быть массивом или массивами... Вот что я получаю, используя ваше решение: '[" type,title,amount","expense,Rent,1900","expense,Hydro,100"]' Что мне нужно: '[{"type,title,amount"},{"expense,Rent,1900 "},{"expense,Hydro,100"]}' Возможно, я перепутал терминологию, думаю, мы называем это массивом массива?
Возможно, это сложно понять, но я отредактировал его, добавив что-то, что должно подойти для вашего случая. Было бы лучше использовать существующий пакет, например csv-parse, и импортировать его в реальный проект веб-приложения. Вы можете узнать о Node.js и Express.js, это хорошее место для начала создания веб-приложения.
zzzggghhh, Еще раз спасибо за эту информацию, и как только я закончу этот проект, я рассмотрю Node и Express. Предоставленный вами код работает нормально, за исключением чисел, которые, как я считаю, должны быть числами с плавающей запятой (возможно ли это?). Я не очень хорош в обратном проектировании вашего кода, но с помощью консоли я обнаружил, что это то, что я получаю: 0: {type: 'expense', title: 'Rent', sum: '1900'} где мне нужно это: 0: {type: 'expense', title: 'Rent', sum: 1900} убрать кавычки из номера, я не неблагодарный, я многому учусь, мне бы хотелось купить пользователю кофе на этом сайте .
@ user3146788 В CSV нет типов данных, поэтому вы не можете отличить строку 123 от числа 123. Однако если вы знаете, что в определенном столбце всегда есть числа, вы можете сопоставить значения с числами в конце. Или вы можете реализовать эвристику, в которой вы используете регулярное выражение, например -?\d+(\.\d+)?
, для обнаружения вещей, которые выглядят как числа, а затем преобразуют их в реальные числа.
Привет, CherryDT, ну, у меня не было слов, чтобы описать это так, как у тебя, но это была моя мысль. Способ нацеливания на последний элемент (ключ: количество. значение: число с плавающей запятой) каждой строки, поскольку он всегда будет числом с плавающей запятой. Признаюсь, я пока не совсем понимаю, как я думаю, array.row[2]. Или разрезать массив и собрать его заново, что, как я теперь знаю, является регулярным выражением. Мне придется это изучить. Мне бы хотелось использовать готовый код, предоставленный zzzhhhggg, потому что я в значительной степени понимаю, что там происходит. Мне нужно это число как число с плавающей запятой, потому что остальная часть приложения выполняет несколько математических вычислений, которые теперь не работают.
Вот что я придумал. Кажется, это работает. Спасибо всем, кто помог.
const fileInput = document.getElementById('csv');
const update = async () => {
const [header, ...rows] = (await fileInput.files[0].text()).trim().split(/[\r\n]+/).map(line => line.split(','));
const records = rows.map(row => {
// Assuming the last column is a float
const floatValue = parseFloat(row[row.length - 1]);
// Remove the last element (float value) from the row
const fields = row.slice(0, -1);
// Create the record object with fields and float value
const record = fields.reduce((record, field, i) => Object.assign(record, { [header[i]]: field }), {});
// Add the float value to the record
record[header[header.length - 1]] = floatValue;
return record;
});
// Save data to localStorage
localStorage.setItem("entry_list", JSON.stringify(records));
};
fileInput.addEventListener('change', update);
в чем проблема или проблема вашего кода?