Perfect brings file system operations into your sever-side Swift environment to control how data is stored and retrieved in an accessible way.
First, ensure the PerfectLib
is imported in your Swift file:
import PerfectLib
You are now able to use the File
object to query and manipulate the file system.
Specify the absolute or relative path to the file:
let thisFile = File("/path/to/file/helloWorld.txt")
If you are not familiar with the file path, please read Directory Operations first.
Important: Before writing to a file — even if it is a new file — it must be opened with the appropriate permissions.
To open a file:
try thisFile.open(<OpenMode>,permissions:<PermissionMode>)
For example, to write a file:
let thisFile = File("helloWorld.txt")
try thisFile.open(.readWrite)
try thisFile.write(string: "Hello, World!")
thisFile.close()
For full outlines of OpenMode and PermissionMode values, see their definitions later in this document.
Use the exists
method to return a Boolean value.
thisFile.exists
Return the modification date for the file in the standard UNIX format of seconds since 1970/01/01 00:00:00 GMT, as an integer using:
thisFile.modificationTime
Regardless of how a file reference was defined, both the absolute (real) and internal path can be returned.
Return the "internal reference" file path:
thisFile.path
Return the "real" file path. If the file is a symbolic link, the link will be resolved:
thisFile.realPath
Once a file has been opened for read or write, it is advisable to either close it at a specific place within the code, or by using defer
:
let thisFile = File("/path/to/file/helloWorld.txt")
// Your processing here
thisFile.close()
To remove a file from the file system, use the delete()
method.
thisFile.delete()
This also closes the file, so there is no need to invoke an additional close()
method.
size
returns the size of the file in bytes, as an integer.
thisFile.size
If the file is a symbolic link, the method will return Boolean true
, otherwise false
.
thisFile.isLink
If the file object refers instead to a directory, isDir
will return either a Boolean true
or false
value.
thisFile.isDir
perms
returns the UNIX style permissions for the file as a PermissionMode
object.
thisFile.perms
For example:
print(thisFile.perms)
>> PermissionMode(rawValue: 29092)
Reads up to the indicated number of bytes from the file:
let thisFile = File("/path/to/file/helloWorld.txt")
let contents = try thisFile.readSomeBytes(count: <Int>)
To read a specific byte range of a file's contents, enter the number of bytes you wish to read. For example, to read the first 10 bytes of a file:
let thisFile = File("/path/to/file/helloWorld.txt")
let contents = try thisFile.readSomeBytes(count: 10)
print(contents)
>> [35, 32, 80, 101, 114, 102, 101, 99, 116, 84]
readString
reads the entire file as a string:
let thisFile = File("/path/to/file/helloWorld.txt")
let contents = try thisFile.readString()
Important: Before writing to a file — even if it is a new file — it must be opened with the appropriate permissions.
Use write
to create or rewrite a string to the file using UTF-8 encoding. The method returns an integer which is the number of bytes written.
Note that this method uses the @discardableResult
property, so it can be used without assignment if required.
let bytesWritten = try thisFile.write(string: <String>)
An array of bytes
can also be written directly to a file. The method returns an integer which is the number of bytes written.
Note that this method uses the @discardableResult
property, so it can be used without assignment if required.
let bytesWritten = try thisFile.write(
bytes: <[UInt8]>,
dataPosition: <Int>,
length: <Int>
)
- bytes: The array of UInt8 to write
- dataPosition: Optional. The offset within
bytes
at which to begin writing - length: Optional. The number of bytes to write
Once a file is defined, the moveto
method can be used to relocate the file to a new location in the file system. This can also be used to rename a file if desired. The operation returns a new file object representing the new location.
let newFile = thisFile.moveTo(path: <String>, overWrite: <Bool>)
- path: The path to move the file to
- overWrite: Optional. Indicates that any existing file at the destination path should first be deleted. Default is
false
The method throws PerfectError.FileError
on error.
let thisFile = File("/path/to/file/helloWorld.txt")
let newFile = try thisFile.moveTo(path: "/path/to/file/goodbyeWorld.txt")
Similar to moveTo
, copyTo
copies the file to the new location, optionally overwriting any existing file. However, it does not delete the original file. A new file object is returned representing the new location.
Note that this method uses the @discardableResult
property, so it can be used without assignment if required.
let newFile = thisFile.copyTo(path: <String>, overWrite: <Bool>)
- path: The path to copy the file to
- overWrite: Optional. Indicates that any existing file at the destination path should first be deleted. Default is
false
The method throws PerfectError.FileError
on error.
let thisFile = File("/path/to/file/helloWorld.txt")
let newFile = try thisFile.copyTo(path: "/path/to/file/goodbyeWorld.txt")
The file locking functions allow sections of a file to be locked with advisory-mode locks.
All the locks for a file are removed when the file is closed or the process terminates.
Note: These are not file system locks, and do not prevent others from performing write operations on the affected files: The locks are "advisory-mode locks".
Attempts to place an advisory lock starting from the current position marker up to the indicated byte count. This function will block the current thread until the lock can be performed.
let result = try thisFile.lock(byteCount: <Int>)
Unlocks the number of bytes starting from the current position marker up to the indicated byte count.
let result = try thisFile.unlock(byteCount: <Int>)
Attempts to place an advisory lock starting from the current position marker up to the indicated byte count. This function will throw an exception if the file is already locked, but will not block the current thread.
let result = try thisFile.tryLock(byteCount: <Int>)
Tests if the indicated bytes are locked. Returns a Boolean true or false.
let isLocked = try thisFile.testLock(byteCount: <Int>)
The OpenMode of a file is defined as an enum:
- .read: Opens the file for read-only access
- .write: Opens the file for write-only access, creating the file if it did not exist
- .readWrite: Opens the file for read-write access, creating the file if it did not exist
- .append: Opens the file for read-write access, creating the file if it did not exist and moving the file marker to the end
- .truncate: Opens the file for read-write access, creating the file if it did not exist and setting the file's size to zero
For example, to write a file:
let thisFile = File("helloWorld.txt")
try thisFile.open(.readWrite)
try thisFile.write(string: "Hello, World!")
thisFile.close()
The PermissionMode for a directory or file is provided as a single option or as an array of options.
For example, to create a directory with specific permissions:
let thisDir = Dir("/path/to/dir/")
do {
try thisDir.create(perms: [.rwxUser, .rxGroup, .rxOther])
} catch {
print("error")
}
//or
do {
try thisDir.create(perms: .rwxUser)
} catch {
print("error")
}
.readUser
: Readable by user.writeUser
: Writable by user.executeUser
: Executable by user.readGroup
: Readable by group.writeGroup
: Writable by group.executeGroup
: Executable by group.readOther
: Readable by others.writeOther
: Writable by others.executeOther
: Executable by others.rwxUser
: Read, write, execute by user.rwUserGroup
: Read, write by user and group.rxGroup
: Read, execute by group.rxOther
: Read, execute by other