In the previous lesson, you saw that each file added to IPFS has its own unique cid
derived from its content. This CID (Content Identifier), can be used like an address to access the file. If you know a file's CID, you can use the cat
method provided by the Regular IPFS Files API—similar to the one you may have seen previously in Unix-style systems—to retrieve its contents like so:
ipfs.cat(ipfsPath, [options])
An IPFS path
can take several forms (you can read about them in the Files API documentation). In this lesson, we'll use the simplest one: the cid
present in the object we receive for a file when the ipfs.add
method is called. You may remember from the previous lesson that the add
method returned both path
and cid
values for each file you added to IPFS. We'll learn more about the difference between these two values later.
The cat
method first searches your own node for the file requested, and if it can't find it there, it will attempt to find it on the broader IPFS network. Because of the way cryptographic hashing works, the content you're searching for is guaranteed to match the file found, regardless of which peer is hosting it.
The cat
method returns an Async Iterable that iterates over the file's chunks of data, i.e. Buffers.
A Buffer
is just a raw collection of bytes and as such doesn't make any assumptions about encodings or the type of data it contains. However, if we know the file being retrieved is a plain text file such as a .txt
, we can convert its buffered contents to a UTF-8 string (an interpretation of those raw bytes) by calling the JavaScript method .toString()
.
But since we have multiple buffers of the same file, we need to reassemble them (concatenate) into a single buffer before converting it into a string. The it-to-buffer
package can do just that: iterate over all of the chunks of the file and put them back together for us.
So if you had the CID for a text file in an IPFS node, you could retrieve the file's contents as a readable string like so:
// the toBuffer variable is globally available (just like ipfs)
const bufferedContents = await toBuffer(ipfs.cat('QmWCscor6qWPdx53zEQmZvQvuWQYxx1ARRCXwYVE4s9wzJ')) // returns a Buffer
const stringContents = bufferedContents.toString() // returns a string
When you're ready to try this in the real world, you should note that the above example can result in heavy memory usage, depending on the contents of the file being read. If you're working with large files and find this to be the case, you might want to skip using the it-to-buffer
package and instead process each chunk of data iteratively. The main reason IPFS now returns Async Iterables
is to provide a built-in option for dealing with potential performance issues.
In ProtoSchool tutorials, our code challenges use small files, so we can concatenate everything without worrying about performance.
For this challenge, we've added a plain text file to your IPFS node for you, and its CID is the following string:
QmWCscor6qWPdx53zEQmZvQvuWQYxx1ARRCXwYVE4s9wzJ
Using the cat
function, retrieve the file's contents and return them as a string.
Hints:
CID
we provide is a string, so it needs to be placed inside quotes. Also, don't forget to convert the buffered contents of the text file to a string using .toString()
before returning your result.ipfs.cat
method returns an Async Iterable
. You can use the package it-to-buffer
to achieve this.Feeling stuck? We'd love to hear what's confusing so we can improve this lesson. Please share your questions and feedback.