anpigon's picture
Add favicon and image assets for Obsidian help and developer documentation
c63ff03
|
raw
history blame
4.83 kB

Each collection of notes in Obsidian is known as a Vault. A Vault consists of a folder, and any sub-folders within it.

While your plugin can access the file system like any other Node.js application, the [[Reference/TypeScript API/Vault/Vault|Vault]] module aims to make it easier to work with files and folders within a Vault.

The following example recursively prints the paths of all Markdown files in a Vault:

const files = this.app.vault.getMarkdownFiles()

for (let i = 0; i < files.length; i++) {
  console.log(files[i].path);
}

If you want to list all files, and not just Markdown documents, use [[getFiles|getFiles()]] instead.

Read files

There are two methods for reading the content of a file: [[Reference/TypeScript API/Vault/read|read()]] and [[cachedRead|cachedRead()]].

  • If you only want to display the content to the user, then use cachedRead() to avoid reading the file from disk multiple times.
  • If you want to read the content, change it, and then write it back to disk, then use read() to avoid potentially overwriting the file with a stale copy.

[!info] The only difference between cachedRead() and read() is when the file was modified outside of Obsidian just before the plugin reads it. As soon as the file system notifies Obsidian that the file has changed from the outside, cachedRead() behaves exactly like read(). Similarly, if you save the file within Obsidian, the read cache is flushed as well.

The following example reads the content of all Markdown files in the Vault and returns the average document size:

import { Notice, Plugin } from "obsidian";

export default class ExamplePlugin extends Plugin {
  async onload() {
    this.addRibbonIcon("info", "Calculate average file length", async () => {
      const fileLength = await this.averageFileLength();
      new Notice(`The average file length is ${fileLength} characters.`);
    });
  }

  async averageFileLength(): Promise<number> {
    const { vault } = this.app;

    const fileContents: string[] = await Promise.all(
      vault.getMarkdownFiles().map((file) => vault.cachedRead(file))
    );

    let totalLength = 0;
    fileContents.forEach((content) => {
      totalLength += content.length;
    });

    return totalLength / fileContents.length;
  }
}

Modify files

To write text content to an existing file, use [[modify|Vault.modify()]].

function writeCurrentDate(vault: Vault, file: TFile): Promise<void> {
  return vault.modify(file, `Today is ${new Intl.DateTimeFormat().format(new Date())}.`);
}

If you want to modify a file based on its current content, use [[process|Vault.process()]] instead. The second argument is a callback that provides the current file content and returns the modified content.

// emojify replaces all occurrences of :) with 🙂.
function emojify(vault: Vault, file: TFile): Promise<string> {
  return vault.process(file, (data) => {
    return data.replace(":)", "🙂");
  })
}

Vault.process() is an abstraction on top of [[Reference/TypeScript API/Vault/read|Vault.read()]] and [[modify|Vault.modify()]] that guarantees that the file doesn't change between reading the current content and writing the updated content. Always prefer Vault.process() over Vault.read()/Vault.modify() to avoid unintentional loss of data.

Asynchronous modifications

[[process|Vault.process()]] only supports synchronous modifications. If you need to modify a file asynchronously:

  1. Read the file using [[cachedRead|Vault.cachedRead()]].
  2. Perform the async operations.
  3. Update the file using [[Reference/TypeScript API/Vault/process|Vault.process()]].

Remember to check that the data in the process() callback is the same as the data returned by cachedRead(). If they aren't the same, that means that the file was changed by a different process, and you may want to ask the user for confirmation, or try again.

Delete files

There are two methods to delete a file, [[delete|delete()]], and [[trash|trash()]]. Which one you should use depends on if you want to allow the user to change their mind.

  • delete() removes the file without a trace.
  • trash() moves the file to the trash bin.

When you use trash(), you have the option to move the file to the system's trash bin, or to a local .trash folder at the root of the user's Vault.

Is it a file or folder?

Some operations return or accept a [[TAbstractFile|TAbstractFile]] object, which can be either a file or a folder. Always check the concrete type of a TAbstractFile before you use it.

const folderOrFile = this.app.vault.getAbstractFileByPath("folderOrFile");

if (folderOrFile instanceof TFile) {
  console.log("It's a file!");
} else if (folderOrFile instanceof TFolder) {
  console.log("It's a folder!");
}