public abstract class

DocumentFile

extends java.lang.Object

 java.lang.Object

↳androidx.documentfile.provider.DocumentFile

Gradle dependencies

compile group: 'androidx.documentfile', name: 'documentfile', version: '1.1.0-alpha01'

  • groupId: androidx.documentfile
  • artifactId: documentfile
  • version: 1.1.0-alpha01

Artifact androidx.documentfile:documentfile:1.1.0-alpha01 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.documentfile:documentfile com.android.support:documentfile

Androidx class mapping:

androidx.documentfile.provider.DocumentFile android.support.v4.provider.DocumentFile

Overview

Representation of a document backed by either a or a raw file on disk. This is a utility class designed to emulate the traditional java.io.File interface. It offers a simplified view of a tree of documents, but it has substantial overhead. For optimal performance and a richer feature set, use the android.provider.DocumentsContract methods and constants directly.

There are several differences between documents and traditional files:

  • Documents express their display name and MIME type as separate fields, instead of relying on file extensions. Some documents providers may still choose to append extensions to their display names, but that's an implementation detail.
  • A single document may appear as the child of multiple directories, so it doesn't inherently know who its parent is. That is, documents don't have a strong notion of path. You can easily traverse a tree of documents from parent to child, but not from child to parent.
  • Each document has a unique identifier within that provider. This identifier is an opaque implementation detail of the provider, and as such it must not be parsed.

Before using this class, first consider if you really need access to an entire subtree of documents. The principle of least privilege dictates that you should only ask for access to documents you really need. If you only need the user to pick a single file, use or . If you want to let the user pick multiple files, add . If you only need the user to save a single file, use . If you use these APIs, you can pass the resulting into DocumentFile.fromSingleUri(Context, Uri) to work with that document.

If you really do need full access to an entire subtree of documents, start by launching to let the user pick a directory. Then pass the resulting into DocumentFile.fromTreeUri(Context, Uri) to start working with the user selected tree.

As you navigate the tree of DocumentFile instances, you can always use DocumentFile.getUri() to obtain the Uri representing the underlying document for that object, for use with , etc.

To simplify your code on devices running or earlier, you can use DocumentFile.fromFile(File) which emulates the behavior of a .

Summary

Methods
public abstract booleancanRead()

Indicates whether the current context is allowed to read from this file.

public abstract booleancanWrite()

Indicates whether the current context is allowed to write to this file.

public abstract DocumentFilecreateDirectory(java.lang.String displayName)

Create a new directory as a direct child of this directory.

public abstract DocumentFilecreateFile(java.lang.String mimeType, java.lang.String displayName)

Create a new document as a direct child of this directory.

public abstract booleandelete()

Deletes this file.

public abstract booleanexists()

Returns a boolean indicating whether this file can be found.

public DocumentFilefindFile(java.lang.String displayName)

Search through DocumentFile.listFiles() for the first document matching the given display name.

public static DocumentFilefromFile(java.io.File file)

Create a DocumentFile representing the filesystem tree rooted at the given java.io.File.

public static DocumentFilefromSingleUri(Context context, Uri singleUri)

Create a DocumentFile representing the single document at the given .

public static DocumentFilefromTreeUri(Context context, Uri treeUri)

Create a DocumentFile representing the document tree rooted at the given .

public abstract java.lang.StringgetName()

Return the display name of this document.

public DocumentFilegetParentFile()

Return the parent file of this document.

public abstract java.lang.StringgetType()

Return the MIME type of this document.

public abstract UrigetUri()

Return a Uri for the underlying document represented by this file.

public abstract booleanisDirectory()

Indicates if this file represents a directory.

public static booleanisDocumentUri(Context context, Uri uri)

Test if given Uri is backed by a .

public abstract booleanisFile()

Indicates if this file represents a file.

public abstract booleanisVirtual()

Indicates if this file represents a virtual document.

public abstract longlastModified()

Returns the time when this file was last modified, measured in milliseconds since January 1st, 1970, midnight.

public abstract longlength()

Returns the length of this file in bytes.

public abstract DocumentFilelistFiles()

Returns an array of files contained in the directory represented by this file.

public abstract booleanrenameTo(java.lang.String displayName)

Renames this file to displayName.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Methods

public static DocumentFile fromFile(java.io.File file)

Create a DocumentFile representing the filesystem tree rooted at the given java.io.File. This doesn't give you any additional access to the underlying files beyond what your app already has.

DocumentFile.getUri() will return file:// Uris for files explored through this tree.

public static DocumentFile fromSingleUri(Context context, Uri singleUri)

Create a DocumentFile representing the single document at the given . This is only useful on devices running or later, and will return null when called on earlier platform versions.

Parameters:

singleUri: the from a successful or request.

public static DocumentFile fromTreeUri(Context context, Uri treeUri)

Create a DocumentFile representing the document tree rooted at the given . This is only useful on devices running or later, and will return null when called on earlier platform versions.

Parameters:

treeUri: the from a successful request.

public static boolean isDocumentUri(Context context, Uri uri)

Test if given Uri is backed by a .

public abstract DocumentFile createFile(java.lang.String mimeType, java.lang.String displayName)

Create a new document as a direct child of this directory.

Parameters:

mimeType: MIME type of new document, such as image/png or audio/flac
displayName: name of new document, without any file extension appended; the underlying provider may choose to append the extension

Returns:

file representing newly created document, or null if failed

See also: android.provider.DocumentsContract

public abstract DocumentFile createDirectory(java.lang.String displayName)

Create a new directory as a direct child of this directory.

Parameters:

displayName: name of new directory

Returns:

file representing newly created directory, or null if failed

See also: android.provider.DocumentsContract

public abstract Uri getUri()

Return a Uri for the underlying document represented by this file. This can be used with other platform APIs to manipulate or share the underlying content. You can use DocumentFile.isDocumentUri(Context, Uri) to test if the returned Uri is backed by a .

See also:

public abstract java.lang.String getName()

Return the display name of this document.

See also:

public abstract java.lang.String getType()

Return the MIME type of this document.

See also:

public DocumentFile getParentFile()

Return the parent file of this document. Only defined inside of the user-selected tree; you can never escape above the top of the tree.

The underlying only defines a forward mapping from parent to child, so the reverse mapping of child to parent offered here is purely a convenience method, and it may be incorrect if the underlying tree structure changes.

public abstract boolean isDirectory()

Indicates if this file represents a directory.

Returns:

true if this file is a directory, false otherwise.

See also:

public abstract boolean isFile()

Indicates if this file represents a file.

Returns:

true if this file is a file, false otherwise.

See also:

public abstract boolean isVirtual()

Indicates if this file represents a virtual document.

Returns:

true if this file is a virtual document.

See also:

public abstract long lastModified()

Returns the time when this file was last modified, measured in milliseconds since January 1st, 1970, midnight. Returns 0 if the file does not exist, or if the modified time is unknown.

Returns:

the time when this file was last modified.

See also:

public abstract long length()

Returns the length of this file in bytes. Returns 0 if the file does not exist, or if the length is unknown. The result for a directory is not defined.

Returns:

the number of bytes in this file.

See also:

public abstract boolean canRead()

Indicates whether the current context is allowed to read from this file.

Returns:

true if this file can be read, false otherwise.

public abstract boolean canWrite()

Indicates whether the current context is allowed to write to this file.

Returns:

true if this file can be written, false otherwise.

See also:

public abstract boolean delete()

Deletes this file.

Note that this method does not throw IOException on failure. Callers must check the return value.

Returns:

true if this file was deleted, false otherwise.

See also: android.provider.DocumentsContract

public abstract boolean exists()

Returns a boolean indicating whether this file can be found.

Returns:

true if this file exists, false otherwise.

public abstract DocumentFile listFiles()

Returns an array of files contained in the directory represented by this file.

Returns:

an array of files.

See also: android.provider.DocumentsContract

public DocumentFile findFile(java.lang.String displayName)

Search through DocumentFile.listFiles() for the first document matching the given display name. Returns null when no matching document is found.

public abstract boolean renameTo(java.lang.String displayName)

Renames this file to displayName.

Note that this method does not throw IOException on failure. Callers must check the return value.

Some providers may need to create a new document to reflect the rename, potentially with a different MIME type, so DocumentFile.getUri() and DocumentFile.getType() may change to reflect the rename.

When renaming a directory, children previously enumerated through DocumentFile.listFiles() may no longer be valid.

Parameters:

displayName: the new display name.

Returns:

true on success.

See also: android.provider.DocumentsContract

Source

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.documentfile.provider;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.File;

/**
 * Representation of a document backed by either a
 * {@link android.provider.DocumentsProvider} or a raw file on disk. This is a
 * utility class designed to emulate the traditional {@link File} interface. It
 * offers a simplified view of a tree of documents, but it has substantial
 * overhead. For optimal performance and a richer feature set, use the
 * {@link android.provider.DocumentsContract} methods and constants directly.
 * <p>
 * There are several differences between documents and traditional files:
 * <ul>
 * <li>Documents express their display name and MIME type as separate fields,
 * instead of relying on file extensions. Some documents providers may still
 * choose to append extensions to their display names, but that's an
 * implementation detail.
 * <li>A single document may appear as the child of multiple directories, so it
 * doesn't inherently know who its parent is. That is, documents don't have a
 * strong notion of path. You can easily traverse a tree of documents from
 * parent to child, but not from child to parent.
 * <li>Each document has a unique identifier within that provider. This
 * identifier is an <em>opaque</em> implementation detail of the provider, and
 * as such it must not be parsed.
 * </ul>
 * <p>
 * Before using this class, first consider if you really need access to an
 * entire subtree of documents. The principle of least privilege dictates that
 * you should only ask for access to documents you really need. If you only need
 * the user to pick a single file, use {@link Intent#ACTION_OPEN_DOCUMENT} or
 * {@link Intent#ACTION_GET_CONTENT}. If you want to let the user pick multiple
 * files, add {@link Intent#EXTRA_ALLOW_MULTIPLE}. If you only need the user to
 * save a single file, use {@link Intent#ACTION_CREATE_DOCUMENT}. If you use
 * these APIs, you can pass the resulting {@link Intent#getData()} into
 * {@link #fromSingleUri(Context, Uri)} to work with that document.
 * <p>
 * If you really do need full access to an entire subtree of documents, start by
 * launching {@link Intent#ACTION_OPEN_DOCUMENT_TREE} to let the user pick a
 * directory. Then pass the resulting {@link Intent#getData()} into
 * {@link #fromTreeUri(Context, Uri)} to start working with the user selected
 * tree.
 * <p>
 * As you navigate the tree of DocumentFile instances, you can always use
 * {@link #getUri()} to obtain the Uri representing the underlying document for
 * that object, for use with {@link ContentResolver#openInputStream(Uri)}, etc.
 * <p>
 * To simplify your code on devices running
 * {@link android.os.Build.VERSION_CODES#KITKAT} or earlier, you can use
 * {@link #fromFile(File)} which emulates the behavior of a
 * {@link android.provider.DocumentsProvider}.
 *
 * @see android.provider.DocumentsProvider
 * @see android.provider.DocumentsContract
 */
public abstract class DocumentFile {
    static final String TAG = "DocumentFile";

    @Nullable
    private final DocumentFile mParent;

    DocumentFile(@Nullable DocumentFile parent) {
        mParent = parent;
    }

    /**
     * Create a {@link DocumentFile} representing the filesystem tree rooted at
     * the given {@link File}. This doesn't give you any additional access to the
     * underlying files beyond what your app already has.
     * <p>
     * {@link #getUri()} will return {@code file://} Uris for files explored
     * through this tree.
     */
    @NonNull
    public static DocumentFile fromFile(@NonNull File file) {
        return new RawDocumentFile(null, file);
    }

    /**
     * Create a {@link DocumentFile} representing the single document at the
     * given {@link Uri}. This is only useful on devices running
     * {@link android.os.Build.VERSION_CODES#KITKAT} or later, and will return
     * {@code null} when called on earlier platform versions.
     *
     * @param singleUri the {@link Intent#getData()} from a successful
     *            {@link Intent#ACTION_OPEN_DOCUMENT} or
     *            {@link Intent#ACTION_CREATE_DOCUMENT} request.
     */
    @Nullable
    public static DocumentFile fromSingleUri(@NonNull Context context, @NonNull Uri singleUri) {
        if (Build.VERSION.SDK_INT >= 19) {
            return new SingleDocumentFile(null, context, singleUri);
        } else {
            return null;
        }
    }

    /**
     * Create a {@link DocumentFile} representing the document tree rooted at
     * the given {@link Uri}. This is only useful on devices running
     * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later, and will return
     * {@code null} when called on earlier platform versions.
     *
     * @param treeUri the {@link Intent#getData()} from a successful
     *            {@link Intent#ACTION_OPEN_DOCUMENT_TREE} request.
     */
    @Nullable
    public static DocumentFile fromTreeUri(@NonNull Context context, @NonNull Uri treeUri) {
        if (Build.VERSION.SDK_INT >= 21) {
            String documentId = DocumentsContractApi.getTreeDocumentId(treeUri);
            if (DocumentsContractApi.isDocumentUri(context, treeUri)) {
                documentId = DocumentsContractApi.getDocumentId(treeUri);
            }
            if (documentId == null) {
                throw new IllegalArgumentException(
                        "Could not get document ID from Uri: " + treeUri);
            }
            Uri treeDocumentUri =
                    DocumentsContractApi.buildDocumentUriUsingTree(treeUri, documentId);
            if (treeDocumentUri == null) {
                throw new NullPointerException(
                        "Failed to build documentUri from a tree: " + treeUri);
            }
            return new TreeDocumentFile(null, context, treeDocumentUri);
        } else {
            return null;
        }
    }

    /**
     * Test if given Uri is backed by a
     * {@link android.provider.DocumentsProvider}.
     */
    public static boolean isDocumentUri(@NonNull Context context, @Nullable Uri uri) {
        return DocumentsContractApi.isDocumentUri(context, uri);
    }

    /**
     * Create a new document as a direct child of this directory.
     *
     * @param mimeType MIME type of new document, such as {@code image/png} or
     *            {@code audio/flac}
     * @param displayName name of new document, without any file extension
     *            appended; the underlying provider may choose to append the
     *            extension
     * @return file representing newly created document, or null if failed
     * @throws UnsupportedOperationException when working with a single document
     *             created from {@link #fromSingleUri(Context, Uri)}.
     * @see android.provider.DocumentsContract#createDocument(ContentResolver,
     *      Uri, String, String)
     */
    @Nullable
    public abstract DocumentFile createFile(@NonNull String mimeType, @NonNull String displayName);

    /**
     * Create a new directory as a direct child of this directory.
     *
     * @param displayName name of new directory
     * @return file representing newly created directory, or null if failed
     * @throws UnsupportedOperationException when working with a single document
     *             created from {@link #fromSingleUri(Context, Uri)}.
     * @see android.provider.DocumentsContract#createDocument(ContentResolver,
     *      Uri, String, String)
     */
    @Nullable
    public abstract DocumentFile createDirectory(@NonNull String displayName);

    /**
     * Return a Uri for the underlying document represented by this file. This
     * can be used with other platform APIs to manipulate or share the
     * underlying content. You can use {@link #isDocumentUri(Context, Uri)} to
     * test if the returned Uri is backed by a
     * {@link android.provider.DocumentsProvider}.
     *
     * @see Intent#setData(Uri)
     * @see Intent#setClipData(android.content.ClipData)
     * @see ContentResolver#openInputStream(Uri)
     * @see ContentResolver#openOutputStream(Uri)
     * @see ContentResolver#openFileDescriptor(Uri, String)
     */
    @NonNull
    public abstract Uri getUri();

    /**
     * Return the display name of this document.
     *
     * @see android.provider.DocumentsContract.Document#COLUMN_DISPLAY_NAME
     */
    @Nullable
    public abstract String getName();

    /**
     * Return the MIME type of this document.
     *
     * @see android.provider.DocumentsContract.Document#COLUMN_MIME_TYPE
     */
    @Nullable
    public abstract String getType();

    /**
     * Return the parent file of this document. Only defined inside of the
     * user-selected tree; you can never escape above the top of the tree.
     * <p>
     * The underlying {@link android.provider.DocumentsProvider} only defines a
     * forward mapping from parent to child, so the reverse mapping of child to
     * parent offered here is purely a convenience method, and it may be
     * incorrect if the underlying tree structure changes.
     */
    @Nullable
    public DocumentFile getParentFile() {
        return mParent;
    }

    /**
     * Indicates if this file represents a <em>directory</em>.
     *
     * @return {@code true} if this file is a directory, {@code false}
     *         otherwise.
     * @see android.provider.DocumentsContract.Document#MIME_TYPE_DIR
     */
    public abstract boolean isDirectory();

    /**
     * Indicates if this file represents a <em>file</em>.
     *
     * @return {@code true} if this file is a file, {@code false} otherwise.
     * @see android.provider.DocumentsContract.Document#COLUMN_MIME_TYPE
     */
    public abstract boolean isFile();

    /**
     * Indicates if this file represents a <em>virtual</em> document.
     *
     * @return {@code true} if this file is a virtual document.
     * @see android.provider.DocumentsContract.Document#FLAG_VIRTUAL_DOCUMENT
     */
    public abstract boolean isVirtual();

    /**
     * Returns the time when this file was last modified, measured in
     * milliseconds since January 1st, 1970, midnight. Returns 0 if the file
     * does not exist, or if the modified time is unknown.
     *
     * @return the time when this file was last modified.
     * @see android.provider.DocumentsContract.Document#COLUMN_LAST_MODIFIED
     */
    public abstract long lastModified();

    /**
     * Returns the length of this file in bytes. Returns 0 if the file does not
     * exist, or if the length is unknown. The result for a directory is not
     * defined.
     *
     * @return the number of bytes in this file.
     * @see android.provider.DocumentsContract.Document#COLUMN_SIZE
     */
    public abstract long length();

    /**
     * Indicates whether the current context is allowed to read from this file.
     *
     * @return {@code true} if this file can be read, {@code false} otherwise.
     */
    public abstract boolean canRead();

    /**
     * Indicates whether the current context is allowed to write to this file.
     *
     * @return {@code true} if this file can be written, {@code false}
     *         otherwise.
     * @see android.provider.DocumentsContract.Document#COLUMN_FLAGS
     * @see android.provider.DocumentsContract.Document#FLAG_SUPPORTS_DELETE
     * @see android.provider.DocumentsContract.Document#FLAG_SUPPORTS_WRITE
     * @see android.provider.DocumentsContract.Document#FLAG_DIR_SUPPORTS_CREATE
     */
    public abstract boolean canWrite();

    /**
     * Deletes this file.
     * <p>
     * Note that this method does <i>not</i> throw {@code IOException} on
     * failure. Callers must check the return value.
     *
     * @return {@code true} if this file was deleted, {@code false} otherwise.
     * @see android.provider.DocumentsContract#deleteDocument(ContentResolver,
     *      Uri)
     */
    public abstract boolean delete();

    /**
     * Returns a boolean indicating whether this file can be found.
     *
     * @return {@code true} if this file exists, {@code false} otherwise.
     */
    public abstract boolean exists();

    /**
     * Returns an array of files contained in the directory represented by this
     * file.
     *
     * @return an array of files.
     * @throws UnsupportedOperationException when working with a single document
     *             created from {@link #fromSingleUri(Context, Uri)}.
     * @see android.provider.DocumentsContract#buildChildDocumentsUriUsingTree(Uri,
     *      String)
     */
    @NonNull
    public abstract DocumentFile[] listFiles();

    /**
     * Search through {@link #listFiles()} for the first document matching the
     * given display name. Returns {@code null} when no matching document is
     * found.
     *
     * @throws UnsupportedOperationException when working with a single document
     *             created from {@link #fromSingleUri(Context, Uri)}.
     */
    @Nullable
    public DocumentFile findFile(@NonNull String displayName) {
        for (DocumentFile doc : listFiles()) {
            if (displayName.equals(doc.getName())) {
                return doc;
            }
        }
        return null;
    }

    /**
     * Renames this file to {@code displayName}.
     * <p>
     * Note that this method does <i>not</i> throw {@code IOException} on
     * failure. Callers must check the return value.
     * <p>
     * Some providers may need to create a new document to reflect the rename,
     * potentially with a different MIME type, so {@link #getUri()} and
     * {@link #getType()} may change to reflect the rename.
     * <p>
     * When renaming a directory, children previously enumerated through
     * {@link #listFiles()} may no longer be valid.
     *
     * @param displayName the new display name.
     * @return true on success.
     * @throws UnsupportedOperationException when working with a single document
     *             created from {@link #fromSingleUri(Context, Uri)}.
     * @see android.provider.DocumentsContract#renameDocument(ContentResolver,
     *      Uri, String)
     */
    public abstract boolean renameTo(@NonNull String displayName);
}