Java tutorial
/* * Copyright (C) 2015 Square, Inc. * * 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 com.squareup.okhttp.internal.io; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import okio.Okio; import okio.Sink; import okio.Source; /** * Access to read and write files on a hierarchical data store. Most callers should use the {@link * #SYSTEM} implementation, which uses the host machine's local file system. Alternate * implementations may be used to inject faults (for testing) or to transform stored data (to add * encryption, for example). * * <p>All operations on a file system are racy. For example, guarding a call to {@link #source} * with {@link #exists} does not guarantee that {@link FileNotFoundException} will not be thrown. * The file may be moved between the two calls! * * <p>This interface is less ambitious than {@link java.nio.file.FileSystem} introduced in Java 7. * It lacks important features like file watching, metadata, permissions, and disk space * information. In exchange for these limitations, this interface is easier to implement and works * on all versions of Java and Android. */ public interface FileSystem { /** The host machine's local file system. */ FileSystem SYSTEM = new FileSystem() { @Override public Source source(File file) throws FileNotFoundException { return Okio.source(file); } @Override public Sink sink(File file) throws FileNotFoundException { try { return Okio.sink(file); } catch (FileNotFoundException e) { // Maybe the parent directory doesn't exist? Try creating it first. file.getParentFile().mkdirs(); return Okio.sink(file); } } @Override public Sink appendingSink(File file) throws FileNotFoundException { try { return Okio.appendingSink(file); } catch (FileNotFoundException e) { // Maybe the parent directory doesn't exist? Try creating it first. file.getParentFile().mkdirs(); return Okio.appendingSink(file); } } @Override public void delete(File file) throws IOException { // If delete() fails, make sure it's because the file didn't exist! if (!file.delete() && file.exists()) { throw new IOException("failed to delete " + file); } } @Override public boolean exists(File file) throws IOException { return file.exists(); } @Override public long size(File file) { return file.length(); } @Override public void rename(File from, File to) throws IOException { delete(to); if (!from.renameTo(to)) { throw new IOException("failed to rename " + from + " to " + to); } } @Override public void deleteContents(File directory) throws IOException { File[] files = directory.listFiles(); if (files == null) { throw new IOException("not a readable directory: " + directory); } for (File file : files) { if (file.isDirectory()) { deleteContents(file); } if (!file.delete()) { throw new IOException("failed to delete " + file); } } } }; /** Reads from {@code file}. */ Source source(File file) throws FileNotFoundException; /** * Writes to {@code file}, discarding any data already present. Creates parent directories if * necessary. */ Sink sink(File file) throws FileNotFoundException; /** * Writes to {@code file}, appending if data is already present. Creates parent directories if * necessary. */ Sink appendingSink(File file) throws FileNotFoundException; /** Deletes {@code file} if it exists. Throws if the file exists and cannot be deleted. */ void delete(File file) throws IOException; /** Returns true if {@code file} exists on the file system. */ boolean exists(File file) throws IOException; /** Returns the number of bytes stored in {@code file}, or 0 if it does not exist. */ long size(File file); /** Renames {@code from} to {@code to}. Throws if the file cannot be renamed. */ void rename(File from, File to) throws IOException; /** * Recursively delete the contents of {@code directory}. Throws an IOException if any file could * not be deleted, or if {@code dir} is not a readable directory. */ void deleteContents(File directory) throws IOException; }