% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/vsifile.R
\name{VSIFile-class}
\alias{VSIFile-class}
\alias{Rcpp_VSIFile}
\alias{Rcpp_VSIFile-class}
\alias{VSIFile}
\title{Class wrapping the GDAL VSIVirtualHandle API for binary file I/O}
\arguments{
\item{filename}{Character string containing the filename to open. It may be
a file in a regular local filesystem, or a filename with a GDAL /vsiPREFIX/
(see \url{https://gdal.org/en/stable/user/virtual_file_systems.html}).}

\item{access}{Character string containing the access requested (i.e., \code{"r"},
\code{"r+"}, \code{"w"}, \verb{"w+}). Defaults to \code{"r"}. Binary access is always implied
and the "b" does not need to be included in \code{access}.
\tabular{lll}{
\strong{Access} \tab \strong{Explanation}             \tab \strong{If file exists}\cr
\code{"r"}      \tab open file for reading       \tab read from start\cr
\code{"r+"}     \tab open file for read/write    \tab read from start\cr
\code{"w"}      \tab create file for writing     \tab destroy contents\cr
\code{"w+"}     \tab create file for read/write  \tab destroy contents
}}

\item{options}{Optional character vector of \code{NAME=VALUE} pairs specifying
filesystem-dependent options. These are the options provided by
\code{VSIFOpenEx2L()} in the GDAL API (GDAL >= 3.3, see Details).}
}
\value{
An object of class \code{VSIFile} which contains a pointer to a
\code{VSIVirtualHandle}. Class methods are described in Details, along with a set
of writable fields for per-object settings.
}
\description{
\code{VSIFile} provides bindings to the GDAL VSIVirtualHandle API. Encapsulates a
\code{VSIVirtualHandle}
(\url{https://gdal.org/en/stable/api/cpl_cpp.html#_CPPv416VSIVirtualHandle}).
This API abstracts binary file I/O across "regular" file systems, URLs,
cloud storage services, Zip/GZip/7z/RAR, and in-memory files.
It provides analogs of several Standard C file I/O functions, allowing
virtualization of disk I/O so that non-file data sources can be made to
appear as files.

\code{VSIFile} is a C++ class exposed directly to \R (via \code{RCPP_EXPOSED_CLASS}).
Fields and methods of the class are accessed using the \code{$} operator.
}
\note{
File offsets are given as \R \code{numeric} (i.e., \code{double} type), optionally
carrying the \code{bit64::integer64} class attribute. They are returned as
\code{numeric} with the \code{integer64} class attribute attached. The \code{integer64}
type is signed, so the maximum file offset supported by this interface
is \code{9223372036854775807} (the value of \code{bit64::lim.integer64()[2]}).

Some virtual file systems allow only sequential write, so no seeks or read
operations are then allowed (e.g., AWS S3 files with /vsis3/).
Starting with GDAL 3.2, a configuration option can be set with:

\if{html}{\out{<div class="sourceCode">}}\preformatted{set_config_option("CPL_VSIL_USE_TEMP_FILE_FOR_RANDOM_WRITE", "YES")
}\if{html}{\out{</div>}}

in which case random-write access is possible (involves the creation of a
temporary local file, whose location is controlled by the \code{CPL_TMPDIR}
configuration option). In this case, setting \code{access} to \code{"w+"} may be
needed for writing with seek and read operations (if creating a new file,
otherwise, \code{"r+"} to open an existing file), while \code{"w"} access would
allow sequential write only.
}
\section{Usage (see Details)}{


\if{html}{\out{<div class="sourceCode">}}\preformatted{## Constructors
vf <- new(VSIFile, filename)
# specifying access:
vf <- new(VSIFile, filename, access)
# specifying access and options (both required):
vf <- new(VSIFile, filename, access, options)

## Read/write fields (per-object settings)
vf$reportVSIFErrorAsEof

## Methods
vf$seek(offset, origin)
vf$tell()
vf$rewind()
vf$read(nbytes)
vf$write(object)
vf$eof()
vf$truncate(new_size)
vf$flush()
vf$ingest(max_size)

vf$close()
vf$open()
vf$get_filename()
vf$get_access()
vf$set_access(access)
}\if{html}{\out{</div>}}
}

\section{Details}{

\subsection{Constructors}{

\code{new(VSIFile, filename)}\cr
Returns an object of class \code{VSIFile}, or an error is raised if a file
handle cannot be obtained.

\code{new(VSIFile, filename, access)}\cr
Alternate constructor for passing \code{access} as a character string
(e.g., \code{"r"}, \code{"r+"}, \code{"w"}, \code{"w+"}).
Returns an object of class \code{VSIFile} with an open file handle, or an error
is raised if a file handle cannot be obtained.

\code{new(VSIFile, filename, access, options)}\cr
Alternate constructor for passing \code{access} as a character string, and
\code{options} as a character vector of "NAME=VALUE" pairs (all arguments
required, GDAL >= 3.3 required for \code{options} support).

The \code{options} argument is highly file system dependent. Supported options
as of GDAL 3.10 include:
\itemize{
\item MIME headers such as Content-Type and Content-Encoding are supported for
the /vsis3/, /vsigs/, /vsiaz/, /vsiadls/ file systems.
\item DISABLE_READDIR_ON_OPEN=YES/NO (GDAL >= 3.6) for /vsicurl/ and other
network-based file systems. By default, directory file listing is done,
unless YES is specified.
\item WRITE_THROUGH=YES (GDAL >= 3.8) for Windows regular files to set the
FILE_FLAG_WRITE_THROUGH flag to the \code{CreateFile()} function. In that mode,
the data are written to the system cache but are flushed to disk without
delay.
}

Options specific to /vsis3/, /vsigs/, /vsioss/ and /vsiaz/:
\itemize{
\item CACHE=YES/NO (GDAL >= 3.10) whether file metadata and content that is read
from the network should be kept cached in memory, after file handle closing.
Default is YES, unless the filename is set in CPL_VSIL_CURL_NON_CACHED.
\item CHUNK_SIZE=val in MiB (GDAL >= 3.10) for "w" mode. Size of a block. Default
is 50 MiB. For /vsis3/, /vsigz/, /vsioss/, it can be up to 5000 MiB.
For /vsiaz/, only taken into account when BLOB_TYPE=BLOCK. It can be up to
4000 MiB.
}

Options specific to /vsiaz/ in "w" mode:
\itemize{
\item BLOB_TYPE=APPEND/BLOCK (GDAL >= 3.10) type of blob. Defaults to APPEND.
Append blocks are limited to 195 GiB (however if the file size is below
4 MiB, a block blob will be created in a single PUT operation).
}

See the GDAL documentation for \code{VSIFOpenEx2L()} for the most current set of
available options (\url{https://gdal.org/en/stable/api/cpl.html}).
}

\subsection{Read/write fields (per-object settings)}{

\code{$reportVSIFErrorAsEof}\cr
A logical value, \code{TRUE} (the default) to report a VSI error condition,
as indicated by \code{VSIFErrorL()} in GDAL >= 3.10, as \code{TRUE} in a call to the
\code{$eof()} method (see below). Since GDAL 3.10, some virtual file systems
that used to report errors through \code{VSIFEofL} now do so through \code{VSIFErrorL}.
Code testing \code{$eof()} to potentially end read loops should also test
for an error condition, which this setting enables by default.
Ignored if GDAL < 3.10.
}

\subsection{Methods}{

\code{$seek(offset, origin)}\cr
Seek to a requested \code{offset} in the file.
\code{offset} is given as a positive numeric scalar, optionally as
\code{bit64::integer64} type.
\code{origin} is given as a character string, one of \code{SEEK_SET}, \code{SEEK_CUR} or
\code{SEEK_END}. Package global constants are defined for convenience, so these
can be passed unquoted. Note that \code{offset} is an unsigned type, so \code{SEEK_CUR}
can only be used for positive seek. If negative seek is needed, use:

\if{html}{\out{<div class="sourceCode">}}\preformatted{vf$seek(vf$tell() + negative_offset, SEEK_SET)
}\if{html}{\out{</div>}}

Returns \code{0} on success or \code{-1} on failure.

\code{$tell()}\cr
Returns the current file read/write offset in bytes from the beginning of
the file. The return value is a numeric scalar carrying the \code{integer64}
class attribute.

\code{$rewind()}\cr
Rewind the file pointer to the beginning of the file. This is equivalent to
\code{vf$seek(0, SEEK_SET)}. No return value, called for that side effect.

\code{$read(nbytes)}\cr
Read \code{nbytes} bytes from the file at the current offset. Returns an \R \code{raw}
vector, or \code{NULL} if the operation fails.

\code{$write(object)}\cr
Write bytes to the file at the current offset. \code{object} is a \code{raw} vector.
Returns the number of bytes successfully written, as numeric scalar
carrying the \code{integer64} class attribute.
See also base \R \code{charToRaw()} / \code{rawToChar()}, convert to or from raw
vectors, and \code{readBin()} / \code{writeBin()} which read binary data from or write
binary data to a raw vector.

\code{$eof()}\cr
Test for end of file. Returns \code{TRUE} if an end-of-file condition occurred
during the previous read operation. The end-of-file flag is cleared by a
successful call to \code{$seek()}.

\code{$truncate(new_size)}\cr
Truncate/expand the file to the specified \code{new_size}, given as a positive
numeric scalar, optionally as \code{bit64::integer64} type.
Returns \code{0} on success.

\code{$flush()}\cr
Flush pending writes to disk. For files in write or update mode and on
file system types where it is applicable, all pending output on the file is
flushed to the physical disk.
On Windows regular files, this method does nothing, unless the
\code{VSI_FLUSH=YES} configuration option is set (and only when the file has not
been opened with the \code{WRITE_THROUGH} option).
Returns \code{0} on success or \code{-1} on error.

\code{$ingest(max_size)}\cr
Ingest a file into memory. Read the whole content of the file into a \code{raw}
vector.
\code{max_size} is the maximum size of file allowed, given as a numeric scalar,
optionally as \code{bit64::integer64} type. If no limit, set to a negative value.
Returns a \code{raw} vector, or \code{NULL} if the operation fails.

\code{$close()}\cr
Closes the file. The file should always be closed when I/O has been
completed. Returns \code{0} on success or \code{-1} on error.

\code{$open()}\cr
This method can be used to re-open the file after it has been closed, using
the same \code{filename}, and same \code{options} if any are set. The file will be
opened using \code{access} as currently set. The \code{$set_access()} method can
be called to change the requested access while the file is closed.
No return value. An error is raised if a file handle cannot be obtained.

\code{$get_filename()}\cr
Returns a character string containing the \code{filename} associated with this
\code{VSIFile} object (the \code{filename} originally used to create the object).

\code{$get_access()}\cr
Returns a character string containing the \code{access} as currently set on this
\code{VSIFile} object.

\code{$set_access(access)}\cr
Sets the requested read/write access on this \code{VSIFile} object, given as a
character string (i.e., \code{"r"}, \code{"r+"}, \code{"w"}, \code{"w+"}). The access can be
changed only while the \code{VSIFile} object is closed, and will apply when it is
re-opened with a call to \code{$open()}.
Returns \code{0} on success or \code{-1} on error.
}
}

\examples{
# The examples make use of the FARSITE LCP format specification at:
# https://gdal.org/en/stable/drivers/raster/lcp.html
# An LCP file is a raw format with a 7,316-byte header. The format
# specification gives byte offets and data types for fields in the header.

lcp_file <- system.file("extdata/storm_lake.lcp", package="gdalraster")

# identify a FARSITE v.4 LCP file
# function to check if the first three fields have valid data
# input is the first twelve raw bytes in the file
is_lcp <- function(bytes) {
  values <- readBin(bytes, "integer", n = 3)
  if ((values[1] == 20 || values[1] == 21) &&
      (values[2] == 20 || values[2] == 21) &&
      (values[3] >= -90 && values[3] <= 90)) {

    return(TRUE)
  } else {
    return(FALSE)
  }
}

vf <- new(VSIFile, lcp_file)
vf

vf$read(12) |> is_lcp()

vf$tell()

# read the whole file into memory
bytes <- vf$ingest(-1)
vf$close()

# write to a VSI in-memory file
mem_file <- "/vsimem/storml_copy.lcp"
vf <- new(VSIFile, mem_file, "w+")
vf$write(bytes)

vf$tell()
vf$rewind()
vf$tell()

vf$seek(0, SEEK_END)
(vf$tell() == vsi_stat(lcp_file, "size"))  # TRUE

vf$rewind()
vf$read(12) |> is_lcp()

# read/write an integer field
# write invalid data for the Latitude field and then set back
# save the original first
vf$seek(8, SEEK_SET)
lat_orig <- vf$read(4)
readBin(lat_orig, "integer")  # 46
# latitude -99 out of range
vf$seek(8, SEEK_SET)
writeBin(-99L, raw()) |> vf$write()
vf$rewind()
vf$read(12) |> is_lcp()  # FALSE
vf$seek(8, SEEK_SET)
vf$read(4) |> readBin("integer")  # -99
# set back to original
vf$seek(8, SEEK_SET)
vf$write(lat_orig)
vf$rewind()
vf$read(12) |> is_lcp()  # TRUE

# read a vector of doubles - xmax, xmin, ymax, ymin
# 327766.1, 323476.1, 5105082.0, 5101872.0
vf$seek(4172, SEEK_SET)
vf$read(32) |> readBin("double", n = 4)

# read a short int, the canopy cover units
vf$seek(4232, SEEK_SET)
vf$read(2) |> readBin("integer", size = 2)  # 1 = "percent"

# read the Description field
vf$seek(6804, SEEK_SET)
bytes <- vf$read(512)
rawToChar(bytes)

# edit the Description
desc <- paste(rawToChar(bytes),
              "Storm Lake AOI,",
              "Beaverhead-Deerlodge National Forest, Montana.")

vf$seek(6804, SEEK_SET)
charToRaw(desc) |> vf$write()
vf$close()

# verify the file as a raster dataset
ds <- new(GDALRaster, mem_file)
ds$info()

# retrieve Description from the metadata
# band = 0 for dataset-level metadata, domain = "" for default domain
ds$getMetadata(band = 0, domain = "")
ds$getMetadataItem(band = 0, mdi_name = "DESCRIPTION", domain = "")

ds$close()
\dontshow{vsi_unlink(mem_file)}
}
\seealso{
GDAL Virtual File Systems (compressed, network hosted, etc...):\cr
/vsimem, /vsizip, /vsitar, /vsicurl, ...\cr
\url{https://gdal.org/en/stable/user/virtual_file_systems.html}

\code{\link[=vsi_copy_file]{vsi_copy_file()}}, \code{\link[=vsi_read_dir]{vsi_read_dir()}}, \code{\link[=vsi_stat]{vsi_stat()}}, \code{\link[=vsi_unlink]{vsi_unlink()}}
}
