Een tekstfile lezen met JavaScript
HTML heeft maar beperkt toegang tot het bestandssysteem van de computer. Het enige wat het kan is een gedownload bestand
opslaan (in een vaststaande map) en aangegeven waar een bestand staat om te uploaden. De map waarin een download wordt opgeslagen
is een browserinstelling. Voor een upload kan naar een map worden genavigeerd in een browser-dialog.
Het is hiermee niet mogelijk om een bestand in te lezen vanaf een cliënt-PC om er in de website iets mee te doen. Met
JavaScript kan het wel.
Op deze pagina wordt uitgelegd hoe je dat doet voor een bestand met alleen platte tekst. Met binaire data kan
het ook, maar dat is ingewikkeld. De binaire data moet nl. worden omgezet in iets waar JavaScript mee overweg kan.
Opmerking: Dit verhaal gaat over het lezen en in je site gebruiken, van een tekstbestand. Het opslaan van een
tekstbestand is mogelijk, maar blijft buiten beschouwing.
Onderaan de vind je links naar voorbeelden. De code van de voorbeelden kun je downloaden om zelf te gebruiken en/of om zelf aan door te ontwikkelen.
- Er worden vier items besproken:
- Het object FileReader().
- De werking van het script.
- Voorbeelden.
- Toepassen in je eigen site.
- Het object FileReader()
- Binnen JavaScript wordt de File API gebruikt. Deze API is beschikbaar in alle grote browsers en heeft diverse mogelijkheden voor het lezen van bestanden en bestandseigenschappen.
- In het voorbeeld wordt het object FileReader()
ingezet. Dit heeft de volgende eigenschappen:
- FileReader.readyState. Een getal dat de status van de FileReader weergeeft. Mogelijke waarden zijn:
• EMPTY (= 0): Nog geen data gelezen.
• LOADING (= 1): De data wordt gelezen.
• DONE (= 2): Alle data is gelezen. - FileReader.result. Bevat de inhoud van de file als de leesactie klaar is. Het format hangt af van de methode waarmee het bestand is gelezen.
- FileReader.error. Dit is een code die aangeeft dat er "ergens" wat fout is gegaan bij het openen of lezen van het bestand.
- FileReader.readyState. Een getal dat de status van de FileReader weergeeft. Mogelijke waarden zijn:
- Het object FileReader heeft vijf methodes:
- FileReader.abort(). Breekt de lopende leesactie af. readyState wordt DONE.
- FileReader.readAsArrayBuffer(). Voor het inlezen van binaire data. Het gebruik van ArrayBuffers wordt beschreven in dit document.
- FileReader.readAsBinaryString(). Dit is een verouderde versie van readAsArrayBuffer. Deze is deprecated (afgeraden) en zal op termijn uit de specificaties verdwijnen. Dit kan nog voorkomen in oudere sites, maar moet in nieuwe sites niet meer gebruikt worden.
- FileReader.readAsDataURL(). Hiermee lees je de inhoud van een bestand in als URL.
- FileReader.readAsText(). Voor het lezen van platte tekst, d.w.z. tekst zonder opmaak, zoals je die in Windows Kladblok hebt. Het kan ook HTML zijn. Op deze pagina wordt FileReader.readAsText() gebruikt.
- Het object FileReader gebruikt zes events, waarop kan worden gereageerd met on...= of addEventListener().
In het laatste geval moet, zodra FileReader niet meer gebruikt wordt, removeEventListener() worden gebruikt
om geheugen-lekken te voorkomen.
- FileReader.abort. Wordt afgevuurd als de leesactie wordt afgebroken. Dat kan door een actie van de gebruiker zijn, maar ook als het JavaScript FileReader.abort() aanroept.
- FileReader.error. Wordt afgevuurd als er een foutconditie ontstaat.
- FileReader.load. Wordt afgevuurd als een leesactie correct is afgesloten.
- FileReader.loadend. Wordt afgevuurd als een leesactie is afgesloten, correct of met een fout.
- FileReader.loadstart. Wordt afgevuurd als een leesactie is gestart.
- FileReader.progress. Wordt met tussenpozen afgevuurd, tijdens het lezen van een bestand.
- De werking van het script
- Een file op de gebruiker-PC kan alleen worden geopend door een actie van de gebruiker zelf. Dit is een veiligheidsmaatregel, die er voor zorgt dat een script niet "zomaar" een bestand kan openen. De gebruiker moet de opdracht geven of op zijn minst toestemming geven om het bestand te openen.
- Op deze site wordt de gebruikers-actie gegarandeerd door gebruik van <input type="file">. Hierdoor
moet de gebruiker eerst een knop indrukken, naar het bestand navigeren en nogmaals knop indrukken om het te openen.
- Allereerst wordt een bestandsnaam opgehaald. Als de file werkelijk blijkt te bestaan wordt die gelezen en beschikbaar gesteld om te gebruiken. Het script is daarmee gereed. Het FileReader-object verdwijnt.
- De code bestaat uit HTML en JavaScript. CSS wordt wel gebruikt, maar is voor de voorbeelden niet relevant.
- HTML
- De HTML voor het openen van een bestand bestaat uit één input-tag met type="file", een id en het attribuut accept, waarin de extensie van soort in te lezen bestanden staat bijv. ".txt" of ".csv".
- Voor het tonen van de inhoud van de file is extra HTML (en CSS en mogelijk JavaScript) nodig, zoiets als <p>,
<div> of <pre>. Die laatste heeft de voorkeur als de oorspronkelijke opmaak van het tekstdocument
behouden moet blijven.
- <input type="file"> maakt een knop met de tekst "Bestand kiezen", met daarbij de tekst "Geen bestand gekozen". Als er een bestand is gekozen wordt "Geen bestand gekozen" vervangen door de naam van het bestand. Die teksten worden door de browser gegenereerd in combinatie met de taalinstelling van het Operating System. Ze kunnen niet worden aangepast. Je kunt ze wel onzichtbaar maken door met CSS color:transparent in te stellen.
- Met Windows en Linux wordt de map waar je het laatst een bestand hebt geopend door de browser onthouden.
- JavaScript
- Het JavaScript voor het lezen van een file moet in de body staan, ná de input-tag.
- Er is alleen een EventListener die reageert als het file-navigatie dialog is veranderd en die het volgende doet:
- Er wordt een constante gedefinieerd (in het voorbeeld: file), waar de naam van het gekozen bestand in wordt gezet. Die naam wordt gehaald uit event.target.files[0]. Dit verwijst naar de naam van het gekozen bestand, die wordt opgeslagen op positie [0] van de array files van het object FilesList binnen de File API.
- Als de file niet bestaat, gebeurt er niets. Deze conditie treedt op als de file wordt verwijderd nádat de applicatie is gestart en vóórdat de keuze wordt gemaakt. In de praktijk zal dat nauwelijks voorkomen.
- Als de file wel bestaat, wordt een nieuw FileReader-object gemaakt.
- Vervolgens wordt een event-handler gedefinieerd die actief wordt als het bestand helemaal is gelezen (en load wordt afgevuurd).
- Tenslotte wordt het bestand ingelezen met readAsText(file).
- De event-handler zet de gelezen data in een constante, in het voorbeeld is dat content. Dit wordt met innerText in het document gezet. Voor deze toepassing is dat het meest geschikt.
- Gelezen data in het document zetten kan op drie manieren, die net even anders werken: met innerHTML, innerText en textContent.
- Met innerHTML krijg je de volledige inhoud van het element. Alle tags worden door de browser verwerkt.
- Met innerText krijg je hetzelfde als met innerHTML, maar HTML-tags worden niet verwerkt, behalve <script> en <style>. Het element erft geen CSS van bovenliggende elementen.
- Met textContent krijg je de volledige inhoud van het element, maar zonder tags.
- Voorbeelden
- Voorbeeld 1: Een tekstfile (.txt) wordt ingelezen en in het window getoond. Hiervoor worden in HTML <pre> (pre-formatted text) en in JavaScript innerText ingezet.
- Nodig is dat er een dergelijk bestand beschikbaar is. Zo nodig maak je er zelf een, bijvoorbeeld met Windows kladblok.
De file-extensie moet .txt zijn.
Toon voorbeeld 1.
- Voorbeeld 2: Een data-bestand wordt ingelezen uit een tekstbestand. De data zijn onderverdeeld in records, één record per tekstregel. De records worden in een array gezet. De datavelden binnen elk record zijn gescheiden door een ; (punt-komma). Die zijn eenvoudig in een aparte array te zetten, zodat elk dataveld beschikbaar is. Houd er daarbij rekening mee dat het laatste dataveld alleen een "\r" (carriage return) bevat.
- De code van het voorbeeld toont de afzonderlijke records in het console met console.log(). In de meeste browsers maak je het console zichtbaar door op functietoets 12 (F12) de drukken.
- Een dergelijk bestand maak je bijvoorbeeld met Microsoft Excel en heeft de extensie .csv.
Toon voorbeeld 2.
- Toepassen in je eigen site
- Download de zip-file en pak hem uit. De bestanden html-777 voorbeeld 1.htm en html-777 voorbeeld 2.htm zijn werkende uitvoeringen van de twee voorbeelden op deze pagina.
- Houd (bij voorbeeld 2) de geldigheid van de array CSVlines in de gaten. De aangewezen methode is om CSVlines te declareren in de <head>. Dat kan met een <script>-tag zoals in voorbeeld 2, of een die verwijst naar een apart .js-bestand.
- Tenslotte...
- Als het mogelijk is om data van een bestand op de gebruikers-PC te lezen, ligt de vraag voor de hand of het mogelijk is
om gelezen en bewerkte data weer op te slaan op de PC. Met de hier gebruikte File-API kan dat niet..
File System API's waarmee bestanden kunnen worden opgeslagen bestaan wel, maar de toepassing ervan is lastig. Daarbij is de ondersteuning, met name door Safari van Apple, beperkt.
Gebruik:
- De code van voorbeeld 1 staat helemaal in de <BODY>.
- Bij voorbeeld 2 staat de code voor het lezen van het bestand helemaal in de <BODY>. Code voor het bewerken van de data kan ook in de <HEAD> staan, eventueel in een apart bestand.
De code van voorbeeld 1 ziet er als volgt uit:
(Zet dit in de <BODY> op de plaats waar de knop "Kies Bestand" moet verschijnen.)
<input type="file" id="fileInput" accept=".txt">
<pre id="output"></pre>
<script>
document.getElementById('fileInput').addEventListener('change', function(event) {
const file = event.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
const content = e.target.result;
document.getElementById('output').innerText = content;
};
reader.readAsText(file);
}
});
</script>
De code van voorbeeld 2 ziet er als volgt uit:
(Zet dit in de <HEAD>).
<script>
let CSVlines, CSVcells;
function runProgram() { // Stuur de eerste regel naar het console, gevolgd door de datavelden van de eerste regel
console.log(CSVlines[0]);
CSVcells = CSVlines[0].split(";");
console.log(CSVcells);
}
</script>
(Zet dit in de <BODY> op de plaats waar de knop "Kies Bestand" moet verschijnen.)
input type="file" id="fileInput" accept=".csv">
<script>
document.getElementById('fileInput').addEventListener('change', function(event) {
const file = event.target.files[0];
CSVfileName = file.name;
if (file) {
const reader = new FileReader();
reader.readAsText(file);
reader.onload = function() {
const content = reader.result;
CSVlines = content.toString().split("\n");
runProgram(); // Hier wordt de array CSVlines verder bewerkt
}
}
});
</script>
Downloaden:
Druk op de knop:
File: voorb777.zip, 1516 bytes.