FileStream is a basic interface for reading and writing files synchronously or asynchronously with support for seeking to an offset. Generally speaking, we normally use asynchronous mode on a TYPE_IO Thread, because it’s more effective. Note that even when used asynchronously, only one operation is supported at a time.

FileStream class declare

class NET_EXPORT FileStream {
 public:
  // Creates a |FileStream| with a new |BoundNetLog| (based on |net_log|)
  // attached.  |net_log| may be NULL if no logging is needed.
  // Uses |task_runner| for asynchronous operations.
  FileStream(net::NetLog* net_log,
             const scoped_refptr<base::TaskRunner>& task_runner);

  
  // |flags| is a bitfield of base::PlatformFileFlags when the file handle was
  // opened.
  FileStream(base::PlatformFile file,
             int flags,
             net::NetLog* net_log,
             const scoped_refptr<base::TaskRunner>& task_runner);

  // The underlying file is closed automatically.
  virtual ~FileStream();

  // Call this method to open the FileStream asynchronously.  The remaining
  // methods cannot be used unless the file is opened successfully. Returns
  // ERR_IO_PENDING if the operation is started. If the operation cannot be
  // started then an error code is returned.
  //
  // Once the operation is done, |callback| will be run on the thread where
  // Open() was called, with the result code. open_flags is a bitfield of
  // base::PlatformFileFlags.
  virtual int Open(const base::FilePath& path, int open_flags,
                   const CompletionCallback& callback);

  // Returns ERR_IO_PENDING and closes the file asynchronously, calling
  // |callback| when done.
  virtual int Close(const CompletionCallback& callback);

  // Closes the file immediately and returns OK. If the file is open
  // asynchronously, Close(const CompletionCallback&) should be used instead.
  virtual int CloseSync();

  // Returns true if Open succeeded and Close has not been called.
  virtual bool IsOpen() const;

  // Adjust the position from where data is read asynchronously.
  // Upon success, ERR_IO_PENDING is returned and |callback| will be run
  // on the thread where Seek() was called with the the stream position
  // relative to the start of the file.  Otherwise, an error code is returned.
  // It is invalid to request any asynchronous operations while there is an
  // in-flight asynchronous operation.
  virtual int Seek(Whence whence, int64 offset,
                   const Int64CompletionCallback& callback);

  // Adjust the position from where data is read synchronously.
  // Upon success, the stream position relative to the start of the file is
  // returned.  Otherwise, an error code is returned.  It is not valid to
  // call SeekSync while a Read call has a pending completion.
  virtual int64 SeekSync(Whence whence, int64 offset);

  // Returns the number of bytes available to read from the current stream
  // position until the end of the file.  Otherwise, an error code is returned.
  virtual int64 Available();

  // Call this method to read data from the current stream position
  // asynchronously. Up to buf_len bytes will be copied into buf.  (In
  // other words, partial reads are allowed.)  Returns the number of bytes
  // copied, 0 if at end-of-file, or an error code if the operation could
  // not be performed.
  //
  // The file must be opened with PLATFORM_FILE_ASYNC, and a non-null
  // callback must be passed to this method. If the read could not
  // complete synchronously, then ERR_IO_PENDING is returned, and the
  // callback will be run on the thread where Read() was called, when the
  // read has completed.
  //
  // It is valid to destroy or close the file stream while there is an
  // asynchronous read in progress.  That will cancel the read and allow
  // the buffer to be freed.
  //
  // This method must not be called if the stream was opened WRITE_ONLY.
  virtual int Read(IOBuffer* buf, int buf_len,
                   const CompletionCallback& callback);

  // Call this method to write data at the current stream position
  // asynchronously.  Up to buf_len bytes will be written from buf. (In
  // other words, partial writes are allowed.)  Returns the number of
  // bytes written, or an error code if the operation could not be
  // performed.
  //
  // The file must be opened with PLATFORM_FILE_ASYNC, and a non-null
  // callback must be passed to this method. If the write could not
  // complete synchronously, then ERR_IO_PENDING is returned, and the
  // callback will be run on the thread where Write() was called when
  // the write has completed.
  virtual int Write(IOBuffer* buf, int buf_len,
                    const CompletionCallback& callback);

  // Call this method to open the FileStream synchronously.
  // If the file stream is not closed manually, the underlying file will be
  // automatically closed when FileStream is destructed.
  virtual int OpenSync(const base::FilePath& path, int open_flags);

  // Call this method to read data from the current stream position
  // synchronously. Up to buf_len bytes will be copied into buf. 
  // Returns the number of bytes copied, 0 if at end-of-file, 
  // or an error code if the operation could not be performed.
  virtual int ReadSync(char* buf, int buf_len);

  // Performs the same as ReadSync, but ensures that exactly buf_len bytes
  // are copied into buf.  A partial read may occur, but only as a result of
  // end-of-file or fatal error.  Returns the number of bytes copied into buf,
  // 0 if at end-of-file and no bytes have been read into buf yet,
  // or an error code if the operation could not be performed.
  virtual int ReadUntilComplete(char *buf, int buf_len);

  // Call this method to write data at the current stream position
  // synchronously.  Up to buf_len bytes will be written from buf. (In
  // other words, partial writes are allowed.)  Returns the number of
  // bytes written, or an error code if the operation could not be
  // performed.
  //
  // The file must not be opened with PLATFORM_FILE_ASYNC.
  // This method must not be called if the stream was opened READ_ONLY.
  //
  // Zero byte writes are not allowed.
  virtual int WriteSync(const char* buf, int buf_len);

  // Truncates the file to be |bytes| length. This is only valid for writable
  // files. After truncation the file stream is positioned at |bytes|. The new
  // position is returned, or a value < 0 on error.
  // WARNING: one may not truncate a file beyond its current length on any
  //   platform with this call.
  virtual int64 Truncate(int64 bytes);

  // Forces out a filesystem sync on this file to make sure that the file was
  // written out to disk and is not currently sitting in the buffer. This does
  // not have to be called, it just forces one to happen at the time of
  // calling.
  //
  // The file must be opened with PLATFORM_FILE_ASYNC, and a non-null
  // callback must be passed to this method. If the write could not
  // complete synchronously, then ERR_IO_PENDING is returned, and the
  // callback will be run on the thread where Flush() was called when
  // the write has completed.
  //
  // It is valid to destroy or close the file stream while there is an
  // asynchronous flush in progress.  That will cancel the flush and allow
  // the buffer to be freed.
  //
  // It is invalid to request any asynchronous operations while there is an
  // in-flight asynchronous operation.
  //
  // This method should not be called if the stream was opened READ_ONLY.
  virtual int Flush(const CompletionCallback& callback);

  // Forces out a filesystem sync on this file to make sure that the file was
  // written out to disk and is not currently sitting in the buffer. This does
  // not have to be called, it just forces one to happen at the time of
  // calling.
  //
  // Returns an error code if the operation could not be performed.
  //
  // This method should not be called if the stream was opened READ_ONLY.
  virtual int FlushSync();

  // Turns on UMA error statistics gathering.
  void EnableErrorStatistics();

  // Sets the source reference for net-internals logging.
  // Creates source dependency events between |owner_bound_net_log| and
  // |bound_net_log_|.  Each gets an event showing the dependency on the other.
  // If only one of those is valid, it gets an event showing that a change
  // of ownership happened, but without details.
  void SetBoundNetLogSource(const net::BoundNetLog& owner_bound_net_log);

  // Returns the underlying platform file for testing.
  base::PlatformFile GetPlatformFileForTesting();

 private:
  class Context;

  bool is_async() const { return !!(open_flags_ & base::PLATFORM_FILE_ASYNC); }

  int open_flags_;
  net::BoundNetLog bound_net_log_;

  // Context performing I/O operations. It was extracted into separate class
  // to perform asynchronous operations because FileStream can be destroyed
  // before completion of async operation. Also if async FileStream is destroyed
  // without explicit closing file should be closed asynchronously without
  // delaying FileStream's destructor. To perform all that separate object is
  // necessary.
  scoped_ptr<Context> context_;

  DISALLOW_COPY_AND_ASSIGN(FileStream);
};

Sample

The example below shows how to use FileStream’s APIs asynchronously, helper function ReadFileAsync should be used on thread with type TYPE_IO.

#include "base/bind.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/task_runner.h"
#include "base/files/file_path.h"

#include "net/base/file_stream.h"
#include "net/base/net_errors.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"

#include <assert.h>
#include <string>

namespace internal {

// File basic info
struct FileBasicInfo 
{
  FileBasicInfo() : file_size(0), file_exists(false) {}

  int file_size;
  bool file_exists;
};

// file reader
class FileReader
{
public:
  FileReader( const scoped_refptr<base::TaskRunner>& file_task_runner )
    : file_task_runner_(file_task_runner)
    , stream_(new net::FileStream(NULL, file_task_runner))
    , file_size_(0)
  {
  }

  bool Read( std::wstring const& filePath, 
      base::Callback<void(int,std::string)> completeCallback ) 
  {
    if ( !base::MessageLoop::current() || 
      base::MessageLoop::current()->type() != base::MessageLoop::TYPE_IO ) 
    {
      assert(false && "MUST called on base::Thread IO message_loop");
      return false;
    }

    file_path_ = base::FilePath(filePath);
    complete_callback_ = completeCallback;

    FileBasicInfo* meta_info = new FileBasicInfo();

    file_task_runner_->PostTaskAndReply( FROM_HERE, 
      base::Bind(&FileReader::FetchMetaInfo, file_path_, 
        base::Unretained(meta_info)),
      base::Bind(&FileReader::DidFetchMetaInfo, 
        base::Unretained(this), base::Owned(meta_info)) );

    return true;
  }

private:
  static void FetchMetaInfo(const base::FilePath& file_path, 
      FileBasicInfo* meta_info) 
  {
    base::PlatformFileInfo platform_info;
    meta_info->file_exists = file_util::GetFileInfo(file_path, &platform_info);
    if (meta_info->file_exists) 
    {
      meta_info->file_size = (int)platform_info.size;
    }   
  }

  void DidFetchMetaInfo(const FileBasicInfo* meta_info)
  {
    if (!meta_info->file_exists) 
    {
      // file not exist
      DidReadFileFailed(net::ERR_FILE_NOT_FOUND);
      return;
    }

    if ( meta_info->file_size == 0 ) 
    {
      // empty file
      DidReadFileFailed(net::ERR_FAILED);
      return;
    }
    file_size_ = meta_info->file_size;
    
    if ( !stream_ ) 
    {
      stream_.reset( new net::FileStream(NULL, file_task_runner_) );
    }
    
    int flags = base::PLATFORM_FILE_OPEN | 
      base::PLATFORM_FILE_READ | 
      base::PLATFORM_FILE_ASYNC;
    int rv = stream_->Open(base::FilePath(file_path_), flags,
      base::Bind(&FileReader::DidOpen, base::Unretained(this)));

    if (rv != net::ERR_IO_PENDING)
      DidOpen(rv);
  }

  void DidOpen(int result) 
  {
    if (result != net::OK) {
      // open failed
      DidReadFileFailed(net::ERR_ACCESS_DENIED);
      return;
    }

    read_buffer_ = new net::IOBuffer(file_size_);

    if (file_size_ > 0 ) 
    {// seek to position 0
      int rv = stream_->Seek(net::FROM_BEGIN, 0, 
        base::Bind(&FileReader::DidSeek, base::Unretained(this)));

      if (rv != net::ERR_IO_PENDING) {
        // seek failed
        DidSeek(-1);
      }
    }
  }

  void DidSeek(int64 result)
  {
    if (result != 0) 
    {
      // seek failed
      DidReadFileFailed(net::ERR_FAILED);
      return;
    }

    int rv = stream_->Read(read_buffer_.get(), file_size_,
      base::Bind(&FileReader::DidReadFileData, base::Unretained(this)));

    if ( rv >= 0 ) {
      // Data is immediately available.
      DidReadFileData(rv);
      return;
    }
  }

  void DidReadFileData(int result)
  {
    std::string data = std::string(read_buffer_->data(), file_size_);
    complete_callback_.Run( net::OK, data );
  }

  void DidReadFileFailed(int result)
  {
    complete_callback_.Run(result, "");
  }

private:
  const scoped_refptr<base::TaskRunner> file_task_runner_;
  scoped_ptr<net::FileStream> stream_;
  scoped_refptr<net::IOBuffer> read_buffer_;
  base::FilePath file_path_;
  int file_size_;
  base::Callback<void(int,std::string)> complete_callback_;
};

// ReadFileAsyncHelper
class ReadFileAsyncHelper 
  : public base::RefCountedThreadSafe<ReadFileAsyncHelper>
{
public:
  ReadFileAsyncHelper(const scoped_refptr<base::TaskRunner>& file_task_runner, 
      std::wstring const& filePath, 
      base::Callback<void(int,std::string)> completeCallback) 
    : file_reader_( new FileReader(file_task_runner) ) 
    , complete_callback_(completeCallback)
    , file_path_(filePath)
  {
  }

  bool Start()
  {// Reference of this is token by callback to FileReader, 
   // which is only released in callback
    return file_reader_->Read(file_path_, 
      base::Bind(&ReadFileAsyncHelper::OnReadComplete, this));
  }

private:
  void OnReadComplete( int status, std::string data )
  {
    complete_callback_.Run(status, data);
    delete file_reader_;
    file_reader_ = NULL;
  }

private:
  FileReader * file_reader_;
  std::wstring file_path_;
  base::Callback<void(int,std::string)> complete_callback_;
};

}//namespace internal

// Read file async
// When the file is read, callback will be called on the call thread
inline bool ReadFileAsync( 
  const scoped_refptr<base::TaskRunner>& file_task_runner, 
  std::wstring const& filePath, 
  base::Callback<void(int,std::string)> completeCallback )
{
  scoped_refptr<internal::ReadFileAsyncHelper> readHelper 
    = new internal::ReadFileAsyncHelper( file_task_runner, 
        filePath, completeCallback );
  return readHelper->Start();
}