简体   繁体   中英

How to load a txt/csv file into javascript string/array while offline

I have a small html/javascript webpage that I want to run in a browser offline.

In the same way the page can include an image or a css file and use it while offline, I want to include a 3mb spreadsheet that the javascript reads into a 2d-array, and I'm hoping for something that would work on IE8 as well as modern browsers.

C:\Folder\index.html
C:\Folder\code.js
C:\Folder\picture.png
C:\Folder\spreadsheet.csv

I've found multiple methods online like

<script src="jquery-csv.js"></script>
var table = $.csv.toArrays("spreadsheet.csv");

or

d3.text('spreadsheet.csv', function(error, _data){
            var table = d3.csv.parseRows(_data);
        });

or

$(document).ready(function() {
    $.ajax({
        type: "GET",
        url: "data.txt",
        dataType: "text",
        success: function(data) {processData(data);}
     });
});

But I tend to get same-origin policy errors such as:

XMLHttpRequest cannot load file://data.txt. Received an invalid response. Origin 'null' is therefore not allowed access.

Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match. 

I can't seem to get these to work offline. How could I accomplish this?

Edit:

I'm managed to get the following to work for a text file only on Firefox using the CSVToArray function found here , which is pretty sluggish with a file of this size, and a hidden iframe .

Ultimately, it would be preferable if this was capable of running on IE8, and if I used a csv rather than a txt file, but at least it's a start.

<iframe style="display:none;" id='text' src = 'file.txt' onload='read_text_file()'>
</iframe>

<script type="text/javascript" >

function read_text_file() {
    var text = document.getElementById('text').contentDocument.body.firstChild.innerHTML;
    var table = CSVToArray(text); 
}

For IE8 I managed to get this to work on a small scale but with the 3mb file it will occasionally crash the browser and will always accost the user with both a ton of warning messages that activex is being used and a wave of warnings that the script will slow down the computer.

    window.onLoad = readFileInIE("file.csv");

    function readFileInIE(filePath) {

        try {
            var fso = new ActiveXObject("Scripting.FileSystemObject");      
            var file = fso.OpenTextFile(filePath, true);                                    
            var text = file.ReadAll();  
            var table = CSVToArray(text);
            file.Close();

            return fileContent;
        } catch (e) {
            if (e.number == -2146827859) {
                alert('Unable to access local files due to browser security settings. ' + 
                    'To overcome this, go to Tools->Internet Options->Security->Custom Level. ' + 
                    'Find the setting for "Initialize and script ActiveX controls not marked as safe" and change it to "Enable" or "Prompt"'); 
            }
        }
    }

This might not work in IE8, but the HTML5 API is really useful for this. Just use:

window.onload = function() {
    var fileInput = document.getElementById('fileInput');             

    fileInput.addEventListener('change', function(e) {
        var file = fileInput.files[0];
        var textType = //format you'd like to recieve;
        if (file.type.match(textType)) {
            var reader = new FileReader();              
            reader.onload = function(e) {
                // apply magic here
            }
            reader.readAsText(file);
        }
        else
        {
            fileDisplayArea.innerText ="Sorry matey, can't help you with that filetype."
        }
    });    
}

Then after that, a simple .html file that looks like this would do the trick:

<html lang="en">
    <head>        
        <script src="script.js"></script>          
    </head>
    <body>
        <div id="page-wrapper">
            <div> 
                <input type="file" id="fileInput">
            </div>
            <pre id="fileDisplayArea"></pre> //display any output here
        </div>
    </body>
</html>

It's not quite clear what you want to do.

Using jQuery it's possible to modify events that happen in the DOM. Using this you could potentially save the source code when you're done making changes. You would then need to replace your current source code with the saved code to use the changes the next time you open up the page. However, this would be a very laborious process and there are likely a number of better ways to accomplish what you want to do depending on what that is.

Also, in regards to Shota's post. You can't use AJAX unless you have a server running in the background. If you decide to set the system up on a server there are a number of options for accomplishing what you want.

As you have realized, any AJAX-based solution will be affected by security restrictions for local file access. Instead of finding browser-specific workarounds, you could go the JSONP way which avoids AJAX.

This would require you to pre-process your CSV data and save it in a more JS-friendly format . But this would be a good idea anyway, as native JS parsing is likely to perform better than a CSV parser implemented in JS.

It could look roughly like this:

index.html

    </head>
    <body>
        <div id="page-wrapper">
        <div> 
            <input type="file" id="fileInput">
        </div>
        <pre id="fileDisplayArea"></pre> <!-- display any output here -->

        </div>
        <script src="script.js"></script>
        <script src="data.js"></script>
    </body>
</html>

script.js

function processData(data) {
    // Your logic
    // (will be called once data.js is loaded)
}

data.js

processData([
    ["your", "data"]
]);

My comment become too long.

You can't include data files in the same way as media. The easiest way would be to preprocess the csv into a js array and then include the csv like js <script src="mydata.csv.js"></script> .

By offline you mean local files and not public? The first suggestion would be to upgrade your browser. It doesn't quiet make sense if its a local file supporting all major browsers. Sorry I'm sure you have reasons why you can't. But upgrading would get around the non Ecmascript 5 support in ie8.

To get around the cross origin policy you'd have to run your file on a local webserver. So your html page would be on something like localhost:8080 and your csv localhost:8080/mydata.csv this gives privileges to the html to allow access to the csv file as they're now on the same domain. D3, jquerycsv should now work. Its a big security risk allowing any html file to access the filesystem freely.

If a local server isn't an option. You have to select the file each time you load with an input field. This grants the browser permissions to access this file.

After selecting the file, to read the contents for the main browsers (with Ecma5) look into FileReader on MDN , and an example of use can be found here . For ie8 + 9 there is VBscript support to read files. You can use VB just like JS using <script type="text/vbscript"></script>

If you really want to access local resources from a sever page then you need also a local page that allows the access. A local HTML page inside an <iframe> could read the text file and post contents to the main page via window.postMessage() .

There might also be a way with HTML5 iframes and the sandbox attribute, but not in IE9 and below.

see:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM