201

Is there local file manipulation that's been done with JavaScript? I'm looking for a solution that can be accomplished with no install footprint like requiring Adobe AIR.

Specifically, I'd like to read the contents from a file and write those contents to another file. At this point I'm not worried about gaining permissions and am just assuming I already have full permissions to these files.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jared
  • 5,977
  • 10
  • 38
  • 48

14 Answers14

164

Just an update of the HTML5 features is in http://www.html5rocks.com/en/tutorials/file/dndfiles/. This excellent article will explain in detail the local file access in JavaScript. Summary from the mentioned article:

The specification provides several interfaces for accessing files from a 'local' filesystem:

  1. File - an individual file; provides readonly information such as name, file size, MIME type, and a reference to the file handle.
  2. FileList - an array-like sequence of File objects. (Think <input type="file" multiple> or dragging a directory of files from the desktop).
  3. Blob - Allows for slicing a file into byte ranges.

See Paul D. Waite's comment below.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Horst Walter
  • 13,663
  • 32
  • 126
  • 228
  • 8
    It's not exactly a true filesystem like what we have using Java or Flash plugin. For example, we can't list the files on the user's Desktop unless he first selects them himself. – Pacerier May 01 '14 at 20:36
  • 10
    Looks like these APIs are being abandoned: see http://www.w3.org/TR/file-writer-api/ and http://www.html5rocks.com/en/tutorials/file/filesystem/ – Paul D. Waite May 23 '14 at 13:49
  • 4
    Careful there, given the W3C's form for snatching away useful technology. The filesystem api, only implemented in chrome, is not going forward. The _file_ api, [has universal](http://caniuse.com/#search=file) support, is accepted as a [w3c working draft](http://www.w3.org/TR/FileAPI/) and we can no longer imagine life without it. Of course we're still in a browser, and we have to wait til the user brings us the file, but this dramatically extends the reach of web apps and is not going away anytime soon. – bbsimonbb Dec 02 '15 at 09:42
97

If the user selects a file via <input type="file">, you can read and process that file using the File API.

Reading or writing arbitrary files is not allowed by design. It's a violation of the sandbox. From Wikipedia -> Javascript -> Security:

JavaScript and the DOM provide the potential for malicious authors to deliver scripts to run on a client computer via the web. Browser authors contain this risk using two restrictions. First, scripts run in a sandbox in which they can only perform web-related actions, not general-purpose programming tasks like creating files.

2016 UPDATE: Accessing the filesystem directly is possible via the Filesystem API, which is only supported by Chrome and Opera and may end up not being implemented by other browsers (with the exception of Edge). For details see Kevin's answer.

Community
  • 1
  • 1
Chase Seibert
  • 15,703
  • 8
  • 51
  • 58
  • 33
    Damn. This is stupid, of course. Javascript is supposedly an application-agnostic scripting language. Not every application is a web browser. I came here because I'm interested in scripting Photoshop, for instance. Even if some applications don't provide file access classes, it makes sense to standardize them for those applications where they are appropriate - a standard but optional feature, so experience from one app is transferable even if not universally applicable. What I learn in Photoshop won't be portable even to other Javascript hosts that allow file access. –  Jun 12 '10 at 22:28
  • 27
    Javascript the language and do whatever the hosting environment allows it to do. SpiderMonkey can do anything any other language can do. Javascript in the **Browser** is sandboxed. –  Apr 26 '11 at 22:09
  • 35
    This answer might have been correct 3 years ago, but it's certainly not correct any longer. See @Horst Walter's answer on HTML5. Or go here: http://www.html5rocks.com/en/tutorials/file/dndfiles/ – james.garriss Dec 02 '11 at 13:41
  • @james.garriss Yeah, actually it wasn't super correct three years ago either. This page taught me how to read/write with Firefox back in 2003 http://web.archive.org/web/20031229011919/http://www.captain.at/programming/xul/ (bulit for XUL but available in the browser with XpCom) and Microsoft had node.js-style javscript shell scripting in the 1990s (and FileIO available in the browser with ActiveX) – original_username Oct 12 '13 at 13:17
  • @Ian Campbell - Try reading the whole comment before replying to it. If you did that you'd know I know about filesystem access in the Photoshop variant of Javascript, but I also know that it's e.g. completely different to filesystem access in the old Macromedia Flash MX2004 variant of Javascript. Of course since Adobe bought Macromedia, they've obviously standardized, but what about other vendors? As I said, "Even if some applications don't provide file access classes, it makes sense to standardize them for those applications where they are appropriate - a standard but optional feature..." –  Dec 17 '15 at 02:31
  • @Ian Campbell - That may have happened by now, though - I haven't kept up with the changes in Javascript / ECMAscript. –  Dec 17 '15 at 02:32
  • @james.garriss: I've updated and corrected the answer, because both the question asker and the answerer haven't been on SO in years, and this is the accepted answer. – Dan Dascalescu Aug 25 '16 at 00:30
22

UPDATE This feature is removed since Firefox 17 (see https://bugzilla.mozilla.org/show_bug.cgi?id=546848).


On Firefox you (the programmer) can do this from within a JavaScript file:

netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserWrite");

and you (the browser user) will be prompted to allow access. (for Firefox you just need to do this once every time the browser is started)

If the browser user is someone else, they have to grant permission.

Muntashir Akon
  • 8,740
  • 2
  • 27
  • 38
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • 6
    This gives an error that it is deprecated and you can only do this in an extension, not website javascript – Esailija Nov 29 '12 at 11:39
  • 4
    as this link shows, this feature has been removed in later firefox versions. http://support.mozilla.org/en-US/questions/944433 – Makan Jun 06 '13 at 12:09
  • 4
    oh, that sucks. I get security and all that, but we need a way of granting trust to run our own javascript files locally. – Jason S Jun 06 '13 at 13:25
  • sure. and I have not found another way to do this yet. – Makan Jun 06 '13 at 14:32
  • 2
    Please update the answer to show that it is deprecated. Thanks. – jpaugh Jun 04 '15 at 23:36
21

As previously mentioned, the FileSystem and File APIs, along with the FileWriter API, can be used to read and write files from the context of a browser tab/window to a client machine.

There are several things pertaining to the FileSystem and FileWriter APIs which you should be aware of, some of which were mentioned, but are worth repeating:

  • Implementations of the APIs currently exist only in Chromium-based browsers (Chrome & Opera)
  • Both of the APIs were taken off of the W3C standards track on April 24, 2014, and as of now are proprietary
  • Removal of the (now proprietary) APIs from implementing browsers in the future is a possibility
  • A sandbox (a location on disk outside of which files can produce no effect) is used to store the files created with the APIs
  • A virtual file system (a directory structure which does not necessarily exist on disk in the same form that it does when accessed from within the browser) is used represent the files created with the APIs

Here are simple examples of how the APIs are used, directly and indirectly, in tandem to do these things:

BakedGoods*

Write file:

bakedGoods.set({
    data: [{key: "testFile", value: "Hello world!", dataFormat: "text/plain"}],
    storageTypes: ["fileSystem"],
    options: {fileSystem:{storageType: Window.PERSISTENT}},
    complete: function(byStorageTypeStoredItemRangeDataObj, byStorageTypeErrorObj){}
});

Read file:

bakedGoods.get({
        data: ["testFile"],
        storageTypes: ["fileSystem"],
        options: {fileSystem:{storageType: Window.PERSISTENT}},
        complete: function(resultDataObj, byStorageTypeErrorObj){}
});

Using the raw File, FileWriter, and FileSystem APIs

Write file:

function onQuotaRequestSuccess(grantedQuota)
{

    function saveFile(directoryEntry)
    {

        function createFileWriter(fileEntry)
        {

            function write(fileWriter)
            {
                var dataBlob = new Blob(["Hello world!"], {type: "text/plain"});
                fileWriter.write(dataBlob);              
            }

            fileEntry.createWriter(write);
        }

        directoryEntry.getFile(
            "testFile", 
            {create: true, exclusive: true},
            createFileWriter
        );
    }

    requestFileSystem(Window.PERSISTENT, grantedQuota, saveFile);
}

var desiredQuota = 1024 * 1024 * 1024;
var quotaManagementObj = navigator.webkitPersistentStorage;
quotaManagementObj.requestQuota(desiredQuota, onQuotaRequestSuccess);

Read file:

function onQuotaRequestSuccess(grantedQuota)
{

    function getfile(directoryEntry)
    {

        function readFile(fileEntry)
        {

            function read(file)
            {
                var fileReader = new FileReader();

                fileReader.onload = function(){var fileData = fileReader.result};
                fileReader.readAsText(file);             
            }

            fileEntry.file(read);
        }

        directoryEntry.getFile(
            "testFile", 
            {create: false},
            readFile
        );
    }

    requestFileSystem(Window.PERSISTENT, grantedQuota, getFile);
}

var desiredQuota = 1024 * 1024 * 1024;
var quotaManagementObj = navigator.webkitPersistentStorage;
quotaManagementObj.requestQuota(desiredQuota, onQuotaRequestSuccess);

Though the FileSystem and FileWriter APIs are no longer on the standards track, their use can be justified in some cases, in my opinion, because:

  • Renewed interest from the un-implementing browser vendors may place them right back on it
  • Market penetration of implementing (Chromium-based) browsers is high
  • Google (the main contributer to Chromium) has not given and end-of-life date to the APIs

Whether "some cases" encompasses your own, however, is for you to decide.

*BakedGoods is maintained by none other than this guy right here :)

Kevin
  • 2,617
  • 29
  • 35
  • The file API is not only supported by Chrome & Opera. And the File API is not removed from the specification. It would be helpful to clearify which "two APIs" you mean if you say they are removed. I think you're talking about the FileWriter and the FileSystem API. – Sebi2020 Nov 14 '20 at 10:50
11

NW.js allows you to create desktop applications using Javascript without all the security restrictions usually placed on the browser. So you can run executables with a function, or create/edit/read/write/delete files. You can access the hardware, such as current CPU usage or total ram in use, etc.

You can create a windows, linux, or mac desktop application with it that doesn't require any installation.

Jaredcheeda
  • 1,657
  • 17
  • 15
  • 1
    It's also possible to access local files using [Electron](https://stackoverflow.com/questions/38067298/saving-files-locally-with-electron), which is a similar framework for JavaScript desktop applications. – Anderson Green Jun 04 '18 at 20:35
6

If you're deploying on Windows, the Windows Script Host offers a very useful JScript API to the file system and other local resources. Incorporating WSH scripts into a local web application may not be as elegant as you might wish, however.

Traphicone
  • 101
  • 5
  • 3
    I'd like the solution to be os-independent (at least between windows and mac), so the windows script host doesn't satisfy it, unless there is a comparable solution for the mac platform – Jared Dec 16 '08 at 17:59
5

If you have input field like

<input type="file" id="file" name="file" onchange="add(event)"/>

You can get to file content in BLOB format:

function add(event){
  var userFile = document.getElementById('file');
  userFile.src = URL.createObjectURL(event.target.files[0]);
  var data = userFile.src;
}
Radek Mezuláník
  • 351
  • 1
  • 5
  • 15
4

FSO.js wraps the new HTML5 FileSystem API that's being standardized by the W3C and provides an extremely easy way to read from, write to, or traverse a local sandboxed file system. It's asynchronous, so file I/O will not interfere with user experience. :)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
kwh
  • 364
  • 1
  • 3
  • 7
2

If you need access to the entire file system on the client, read/write files, watch folders for changes, start applications, encrypt or sign documents, etc. please have a look at JSFS.

It allows secure and unlimited access from your web page to computer resources on the client without using a browser plugin technology like AcitveX or Java Applet. However, a peace of software has to be installed too.

In order to work with JSFS you should have basic knowledge in Java and Java EE development (Servlets).

Please find JSFS here: https://github.com/jsfsproject/jsfs. It's free and licensed under GPL

wimix
  • 574
  • 1
  • 5
  • 16
1

Assuming that any file that JavaScript code might need, should be allowed directly by the user. Creators of famous browsers do not let JavaScript access files generally.

The main idea of the solution is: the JavaScript code cannot access the file by having its local URL. But it can use the file by having its DataURL: so if the user browses a file and opens it, JavaScript should get the "DataURL" directly from HTML instead of getting "URL".

Then it turns the DataURL into a file, using the readAsDataURL function and FileReader object. Source and a more complete guide with a nice example are in:

https://developer.mozilla.org/en-US/docs/Web/API/FileReader?redirectlocale=en-US&redirectslug=DOM%2FFileReader

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Makan
  • 2,508
  • 4
  • 24
  • 39
1

There is a (commercial) product, "localFS" which can be used to read and write entire file-system on client computer.

Small Windows app must be installed and tiny .js file included in your page.

As a security feature, file-system access can be limited to one folder and protected with a secret-key.

https://www.fathsoft.com/localfs

1

I am only mentioning this as no one mentioned this. There's no programming language I am aware of which allows manipulation of the underlying filesystem. All programming languages rely on OS interrupts to actually get these things done. JavaScript that runs in the browser only has browser "interrupts" to work with which generally does not grant filesystem access unless the browser has been implemented to support such interrupts.

This being said the obvious way to have file system access using JavaScript is to use Node.js which does have the capability of interacting with the underlying OS directly.

apokryfos
  • 38,771
  • 9
  • 70
  • 114
0

You have to work with the new file system API in Javascript

window.showSaveFilePicker - which allows us to save a file to a users computer, which we then have read/write access to.

window.showOpenFilePicker - which allows us to open an existing file on a users computer, which we can then read/write to.

window.showDirectoryPicker - which gives us access to a directory, which we can then read/write to.

check tutorial at https://fjolt.com/article/javascript-new-file-system-api

Nitin Shinde
  • 136
  • 9
-5

if you are using angularjs & aspnet/mvc, to retrieve json files, you have to allow mime type at web config

<staticContent>
    <remove fileExtension=".json" />
    <mimeMap fileExtension=".json" mimeType="application/json" />
  </staticContent>
Mohamed.Abdo
  • 2,054
  • 1
  • 19
  • 12