How-to guide
Read and write files
Access the file nodes of a server: read and append content, open files as a stream, check permissions, and handle errors.
How-to guide
Read and write files
Types usedOpcClientOpcNodeIdOpcFileOpcFileModeOpcFileStreamOpcFileInfoOpcFileMethodsSafeOpcFileHandle
According to the OPC UA specification, nodes of the FileType type have defined properties (property nodes) and methods (method nodes). Through them, the client accesses a data stream the same way as a file in the file system. The node only provides information about the content of the logical or physical file. According to the specification, it does not provide a path to the file, even if one exists. The client accesses the file itself through the methods Open, Close, Read, Write, GetPosition, and SetPosition. These methods always process the data as binary. As on any other platform, in OPC UA you pass a mode when you call Open. The mode defines the kind of file access you intend. You can also request exclusive access to a file in OPC UA. After calling Open, the client receives a numeric key for further file access, the file handle. You always pass this handle to the methods Read, Write, GetPosition, and SetPosition. Close an open file with Close as soon as you no longer need it.
You can access nodes of the FileType type manually with the ReadNode and CallMethod methods of the OpcClient class. Alternatively, the OPC UA .NET SDK offers numerous other classes that implement access to such nodes, some of them modeled on .NET. The NodeId defines which file node the client accesses.
Choose the right class
| Class | .NET counterpart | Suitable for |
|---|---|---|
OpcFile | System. | reading or appending entire content in one call (ReadAllText, ReadAllLines, ReadAllBytes, AppendAllText, AppendAllLines) and opening streams (Open, OpenRead, OpenWrite, OpenText, AppendText) |
OpcFileInfo (namespace Opc.) | System. | querying the properties of a file (Exists, Length, Name, MimeType, CanWrite, CanUserWrite) and opening the file |
OpcFileStream | System. | reading, writing, and positioning through the Stream interface, also together with StreamReader, StreamWriter, or CopyTo |
OpcFileMethods | none | calling the methods of the file node (Open, Read, Write, GetPosition, SetPosition, Close) one by one |
OpcFileMode defines the mode for opening: Read, Write, ReadWrite, EraseExisting, and Truncate (write after emptying the file). OpcFile offers no methods that overwrite an entire file in one call (like File.WriteAllText). To write, use a stream opened with OpenWrite or Open.
Read and write entire files
Read the entire content of a text file:
string reportText = OpcFile.ReadAllText(client, "ns=2;s=Machine/Report");Dim reportText As String = OpcFile.ReadAllText(client, "ns=2;s=Machine/Report")Append more text to a text file:
OpcFile.AppendAllText(client, "ns=2;s=Machine/Report", "Lorem ipsum");OpcFile.AppendAllText(client, "ns=2;s=Machine/Report", "Lorem ipsum")Open and read a file with OpcFileStream:
using (var stream = OpcFile.OpenRead(client, "ns=2;s=Machine/Report")) {
var reader = new StreamReader(stream);
while (!reader.EndOfStream)
Console.WriteLine(reader.ReadLine());
}Using stream = OpcFile.OpenRead(client, "ns=2;s=Machine/Report")
Dim reader = New StreamReader(stream)
While Not reader.EndOfStream
Console.WriteLine(reader.ReadLine())
End While
End UsingOpen and write a file with OpcFileStream:
using (var stream = OpcFile.OpenWrite(client, "ns=2;s=Machine/Report")) {
var writer = new StreamWriter(stream);
writer.WriteLine("Lorem ipsum");
writer.WriteLine("dolor sit");
// ...
}Using stream = OpcFile.OpenWrite(client, "ns=2;s=Machine/Report")
Dim writer = New StreamWriter(stream)
writer.WriteLine("Lorem ipsum")
writer.WriteLine("dolor sit")
'...
End UsingRead the entire content as lines or as bytes:
string[] lines = OpcFile.ReadAllLines(client, "ns=2;s=Machine/Recipe");
byte[] content = OpcFile.ReadAllBytes(client, "ns=2;s=Machine/Snapshot");Dim lines As String() = OpcFile.ReadAllLines(client, "ns=2;s=Machine/Recipe")
Dim content As Byte() = OpcFile.ReadAllBytes(client, "ns=2;s=Machine/Snapshot")Get file information and open files
The OpcFileInfo class of the Opc.UaFx.Client namespace describes a single file. The Opc.UaFx namespace also contains a class named OpcFileInfo. For this reason, the following examples use the fully qualified type name:
Create an instance of OpcFileInfo:
// The type name is qualified, because the Opc.UaFx namespace declares an OpcFileInfo too.
var file = new Opc.UaFx.Client.OpcFileInfo(client, "ns=2;s=Machine/Report");'The type name is qualified, because the Opc.UaFx namespace declares an OpcFileInfo too.
Dim file = New Opc.UaFx.Client.OpcFileInfo(client, "ns=2;s=Machine/Report")Work with the instance of OpcFileInfo:
if (file.Exists) {
Console.WriteLine("File Length: {0}", file.Length);
if (file.CanUserWrite) {
using (var stream = file.OpenWrite()) {
// Your code to write via stream.
}
}
else {
using (var stream = file.OpenRead()) {
// Your code to read via stream.
}
}
}If file.Exists Then
Console.WriteLine("File Length: {0}", file.Length)
If file.CanUserWrite Then
Using stream = file.OpenWrite()
'Your code to write via stream.
End Using
Else
Using stream = file.OpenRead()
'Your code to read via stream.
End Using
End If
End IfQuery properties and write only if the user is allowed to: CanWrite indicates whether the file is writable at all. CanUserWrite indicates whether the logged-on user is allowed to write it. An OpcFileStream opened for writing takes both into account. Its CanWrite property is true only if both apply:
var file = new Opc.UaFx.Client.OpcFileInfo(client, "ns=2;s=Machine/Recipe");
Console.WriteLine(
"{0}: {1} bytes, {2}",
file.Name,
file.Length,
file.MimeType);
if (file.Exists && file.CanUserWrite) {
using (var stream = file.OpenWrite())
using (var writer = new StreamWriter(stream)) {
writer.Write("Speed=1200");
}
}Dim file = New Opc.UaFx.Client.OpcFileInfo(client, "ns=2;s=Machine/Recipe")
Console.WriteLine( _
"{0}: {1} bytes, {2}", _
file.Name, _
file.Length, _
file.MimeType)
If file.Exists AndAlso file.CanUserWrite Then
Using stream = file.OpenWrite()
Using writer = New StreamWriter(stream)
writer.Write("Speed=1200")
End Using
End Using
End IfProcess large files as a stream
Copy large files: Because OpcFileStream derives from Stream, you copy a file of the server to a local file with CopyTo. The stream reads the content in chunks:
using (var source = OpcFile.OpenRead(client, "ns=2;s=Machine/Snapshot"))
using (var target = File.Create("snapshot.bin")) {
source.CopyTo(target);
}Using source = OpcFile.OpenRead(client, "ns=2;s=Machine/Snapshot")
Using target = IO.File.Create("snapshot.bin")
source.CopyTo(target)
End Using
End UsingWrite at a specific position: With Seek, you set the position within the file, for example to the end to append an entry:
using (var stream = OpcFile.Open(client, "ns=2;s=Machine/Log", OpcFileMode.ReadWrite)) {
stream.Seek(0, SeekOrigin.End);
byte[] entry = Encoding.UTF8.GetBytes("Job started" + Environment.NewLine);
stream.Write(entry, 0, entry.Length);
}Using stream = OpcFile.Open(client, "ns=2;s=Machine/Log", OpcFileMode.ReadWrite)
stream.Seek(0, SeekOrigin.End)
Dim entry As Byte() = Encoding.UTF8.GetBytes("Job started" & Environment.NewLine)
stream.Write(entry, 0, entry.Length)
End UsingCall file methods directly
Through the .NET concept SafeHandle (class SafeOpcFileHandle):
using (var handle = OpcFileMethods.SecureOpen(client, "ns=2;s=Machine/Report", OpcFileMode.ReadWrite)) {
byte[] data = OpcFileMethods.SecureRead(handle, 100);
long position = OpcFileMethods.SecureGetPosition(handle);
OpcFileMethods.SecureSetPosition(handle, position + data[data.Length - 1]);
OpcFileMethods.SecureWrite(handle, new byte[] { 1, 2, 3 });
}Using handle = OpcFileMethods.SecureOpen(client, "ns=2;s=Machine/Report", OpcFileMode.ReadWrite)
Dim data As Byte() = OpcFileMethods.SecureRead(handle, 100)
Dim position As Long = OpcFileMethods.SecureGetPosition(handle)
OpcFileMethods.SecureSetPosition(handle, position + data(data.Length - 1))
OpcFileMethods.SecureWrite(handle, New Byte() {1, 2, 3})
End UsingThrough a numeric file handle:
uint handle = OpcFileMethods.Open(client, "ns=2;s=Machine/Report", OpcFileMode.ReadWrite);
try {
byte[] data = OpcFileMethods.Read(client, "ns=2;s=Machine/Report", handle, 100);
ulong position = OpcFileMethods.GetPosition(client, "ns=2;s=Machine/Report", handle);
OpcFileMethods.SetPosition(client, "ns=2;s=Machine/Report", handle, position + data[data.Length - 1]);
OpcFileMethods.Write(client, "ns=2;s=Machine/Report", handle, new byte[] { 1, 2, 3 });
}
finally {
OpcFileMethods.Close(client, "ns=2;s=Machine/Report", handle);
}Dim handle As UInteger = OpcFileMethods.Open(client, "ns=2;s=Machine/Report", OpcFileMode.ReadWrite)
Try
Dim data As Byte() = OpcFileMethods.Read(client, "ns=2;s=Machine/Report", handle, 100)
Dim position As ULong = OpcFileMethods.GetPosition(client, "ns=2;s=Machine/Report", handle)
OpcFileMethods.SetPosition(client, "ns=2;s=Machine/Report", handle, position + data(data.Length - 1))
OpcFileMethods.Write(client, "ns=2;s=Machine/Report", handle, New Byte() {1, 2, 3})
Finally
OpcFileMethods.Close(client, "ns=2;s=Machine/Report", handle)
End TryOnly file access through OpcFile, OpcFileInfo, OpcFileStream, and SafeOpcFileHandle guarantees that an open file is released even if the Close method is never called. In that case, the OpcClient closes all open files automatically, at the latest when the connection to the server closes. This does not apply if you use the methods of the OpcFileMethods class without the Secure prefix.
The OPC UA specification defines no way to recognize a node as a node of the FileType type and thus as a file node. For this reason, the SDK can identify a file node by its node structure:
if (OpcFileMethods.IsFileNode(client, "ns=2;s=Machine/Report")) {
// Your code to operate on the file node.
}If OpcFileMethods.IsFileNode(client, "ns=2;s=Machine/Report") Then
'Your code to operate on the file node.
End IfHandle errors
If the specified node does not exist or is not a file node, the methods of OpcFile, OpcFileInfo, and OpcFileMethods throw an InvalidOperationException. If the server rejects a method call, the method throws an OpcException with the status of the server. This is the case, for example, if the user is not allowed to write the file or the file is already open for exclusive access. For operations that the mode of the stream does not allow (for example, writing to a stream opened for reading), OpcFileStream throws a NotSupportedException:
try {
string recipe = OpcFile.ReadAllText(client, "ns=2;s=Machine/Recipe");
}
catch (InvalidOperationException) {
// The node does not exist or is not a file node.
}
catch (OpcException ex) {
// The server rejected a file method, e.g. with BadUserAccessDenied.
Console.WriteLine("{0}: {1}", ex.Code, ex.Message);
}Try
Dim recipe As String = OpcFile.ReadAllText(client, "ns=2;s=Machine/Recipe")
Catch ex As InvalidOperationException
'The node does not exist or is not a file node.
Catch ex As OpcException
'The server rejected a file method, e.g. with BadUserAccessDenied.
Console.WriteLine("{0}: {1}", ex.Code, ex.Message)
End TrySecurity
Treat content you read from a server like external input. For example, do not use file names or paths from a file you read for access to the local file system without checking them. Limit the size (Length property) before you read a file into memory completely. Check the CanUserWrite property before you write.
Scope
- The
OpcNodeStreamclass reads large binary values that a server provides not as a file but as the value of a variable (see Large binary values as a stream). - The page Node types in the server chapter describes how a server provides file nodes itself.

