Skip to main content
GameDev.net gamedev.net
🔒 Locked

How to read a local file in javascript

Started by Pepsidog Jul 10, 2019 at 3:54 AM 10 replies 7.1k views
Original Post
Pepsidog
Pepsidog

I want to read a text file that's already in the project folder, but I don't know how. I don't need files from the client, I just need files from the project folder.

I am an indie game developer who enjoys pixel art games.
8Observer8
8Observer8

I use the method that I read in the book: WebGL Programming Guide Authors describe in the Appendix F "Load Shader Programs from Files" how to load text files (GLSL shaders) from the project folder. You can run the JavaScript example in JSFiddle: https://jsfiddle.net/8Observer8/wdn9ubhj/

I wrote a simple example in TypeScript. You can run it in playground by click. My example just get text from here: https://www.w3.org/TR/PNG/iso_8859-1.txt and put it on the page.

Playground

Spoiler


Program.ts



import { TextLoader } from "./TextLoader";

class Program
{
    public static Main(): void
    {
        let filePath = "https://www.w3.org/TR/PNG/iso_8859-1.txt";

        TextLoader.Load(filePath, this.OnLoadFile);
    }

    public static OnLoadFile(fileContent: string): void
    {
        let output = document.getElementById("output");
        output.textContent = fileContent;
    }
}

// Debug Version
Program.Main();

// Release Version
// window.onload = () => Program.Main();

TextLoader.ts




export class TextLoader
{
    public static Load(filePath: string, callback: (fileContent: string) => void): void
    {
        let request = new XMLHttpRequest();

        request.onreadystatechange = () =>
        {
            if (request.readyState === 4 && request.status !== 404)
            {
                callback(request.responseText);
            }
        };

        request.open("GET", filePath, true);
        request.send();
    }
}



8Observer8
8Observer8

The readAsText() method can get the Blob or File instances. I can get the File instance from the FileList that is returned by files[0]:


        let input = document.createElement("input") as HTMLInputElement;
        let file = input.files[0];

But how to create the File instance without the HTML input element? I tried to google but I see examples with the HTML input element.

My current code:


    public static LoadUsingFileReader(
        filePath: string, callback: (fileContent: string) => void): void
    {
        let reader = new FileReader();

        reader.onload = () =>
        {
            callback(reader.result as string);
        }
        
        let input = document.createElement("input") as HTMLInputElement;
        let file = input.files[0];

        reader.readAsText(file);
    }


Prototype
Prototype

Frankly, I'm not sure if you can create a FileList object without an input element, the documentation does not mention it. My guess is it's not allowed to prevent malicious apps from loading local data without the users' consent.

Hope this helps.

8Observer8
8Observer8

I think the FileReader instance can be used only with an input element. If you want to load local data from the server you need to use the XMLHttpRequest instance. Am I right?

This code works if you need to load data from project folder and remote server:


    public static LoadUsingXMLHttpRequest(
        filePath: string, callback: (fileContent: string) => void): void
    {
        let request = new XMLHttpRequest();

        request.onreadystatechange = () =>
        {
            if (request.readyState === 4 && request.status !== 404)
            {
                callback(request.responseText);
            }
        };

        request.open("GET", filePath, true);
        request.send();
    }


Prototype
Prototype

HTTPRequest should work, however Chrome for example will not allow you to load any local data at all, except when running a HTTP server.

8Observer8
8Observer8

I think, we have two different situations:

  1. The program allows to user to load files from his computer (from his hard driver) by click on the "Choose" button. In this case you need to use FileReader
  2. We have some text files in our project folder, for example, levels for our game in text format, OBJ file for 3D models, shader files and so on. And we have to load them from the HTTP server. In this case you need to use XMLHttpRequest

We need some information from topic starter to understand what he wants.

8Observer8
8Observer8

I realised these two situations (XMLHttpRequest and FileReader) in TypeScript.

Playground

Source Code on GitHub

Source Code:

Spoiler

index.html



<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    
    <title>Text File Loader in TypeScript</title>

    <!-- Debug Version -->
    <script data-main="js/RequireConfig" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>

    <!-- Release Version -->
    <!-- <script src="js/bundle.min.js"></script> -->
</head>

<body>
    <input id="input" type="file" accept=".txt">
    

Program.ts



import { TextLoader } from "./TextLoader";

// Playground: https://next.plnkr.co/edit/JgPIlgBpNQK8BwO2?preview

class Program
{
    public static Main(): void
    {
        // FileReader
        let inputElement = document.getElementById("input") as HTMLInputElement;
        if (inputElement === null)
        {
            console.log("Failed to get the \"input\" element.");
            return;
        }
        inputElement.onchange = (ev: Event) =>
        {
            TextLoader.LoadUsingFileReader(inputElement, this.OnLoadFile);
        };

        // XMLHTTPRequest
        let filePath = "https://www.w3.org/TR/PNG/iso_8859-1.txt";
        TextLoader.LoadUsingXMLHttpRequest(filePath, this.OnLoadFile);
    }

    public static OnLoadFile(fileContent: string): void
    {
        let output = document.getElementById("output");
        output.textContent = fileContent;
    }
}

// Debug Version
Program.Main();

// Release Version
// window.onload = () => Program.Main();

RequireConfig.ts



requirejs.config({
    baseUrl: "js"
});

requirejs(["Program"], (Program) => { });

TextLoader.ts




export class TextLoader
{
    public static LoadUsingXMLHttpRequest(
        filePath: string, callback: (fileContent: string) => void): void
    {
        let request = new XMLHttpRequest();

        request.onreadystatechange = () =>
        {
            if (request.readyState === 4 && request.status !== 404)
            {
                callback(request.responseText);
            }
        };

        request.open("GET", filePath, true);
        request.send();
    }

    public static LoadUsingFileReader(
        input: HTMLInputElement,
        callback: (fileContent: string) => void): void
    {
        let reader = new FileReader();

        reader.onload = () =>
        {
            callback(reader.result as string);
        }

        let file = input.files[0];
        reader.readAsText(file);
    }
}

package.json



{
    "name": "text-file-loader_typescript",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "build-debug": "tsc -p tsconfig.debug.json",
        "compile-release": "tsc -p tsconfig.release.json",
        "bundle-release": "browserify public/js/Program.js -o public/js/bundle.js",
        "minify-release": "uglifyjs public/js/bundle.js -o public/js/bundle.min.js",
        "build-release": "npm run compile-release && npm run bundle-release && npm run minify-release"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "@types/requirejs": "^2.1.31"
    }
}

tsconfig.debug.json



{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "sourceMap": true
    }
}

tsconfig.json



{
    "compilerOptions": {
        "target": "es5",
        "module": "amd",
        "sourceMap": false,
        "outDir": "public/js"
    },
    "include": [
        "src/**/*.ts"
    ]
}

tsconfig.release.json



{
    "extends": "./tsconfig.json",
    "compilerOptions": {
        "module": "commonjs"
    }
}

launch.json



{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "Launch Client",
            "url": "http://localhost:8080",
            "webRoot": "${workspaceFolder}/public"
        }
    ]
}



8Observer8
8Observer8

You can keep your TXT files locally on the Plunker playground. For example, you have the TXT file that contains you level like this:

Level_001.txt


10000
00100
00100
00100
20000

Playground

As you can see I read the file with XMLHTTPRequest and print it on the page.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.