Anleitung
Dateien lesen und schreiben
Auf Datei-Nodes eines Servers zugreifen: Inhalte lesen und anhängen, Dateien als Stream öffnen, Rechte prüfen und Fehler behandeln.
Anleitung
Dateien lesen und schreiben
Beteiligte TypenOpcClientOpcNodeIdOpcFileOpcFileModeOpcFileStreamOpcFileInfoOpcFileMethodsSafeOpcFileHandle
Nodes vom Typ FileType haben laut OPC-UA-Spezifikation festgelegte Eigenschaften (Property-Nodes) und Methoden (Methoden-Nodes). Über sie greift der Client auf einen Datenstrom so zu wie auf eine Datei im Dateisystem. Der Node stellt dabei nur Informationen über den Inhalt der logischen oder physischen Datei bereit. Einen eventuell vorhandenen Pfad zur Datei stellt er laut Spezifikation nicht bereit. Auf die Datei selbst greift der Client über die Methoden Open, Close, Read, Write, GetPosition und SetPosition zu. Diese Methoden verarbeiten die Daten immer binär. Wie auf jeder anderen Plattform geben Sie auch in OPC UA beim Aufruf von Open einen Modus an, der die Art des geplanten Dateizugriffs festlegt. Auch in OPC UA können Sie exklusiven Zugriff auf eine Datei anfordern. Nach dem Aufruf von Open erhält der Client einen numerischen Schlüssel für den weiteren Dateizugriff (engl. File Handle). Diesen Schlüssel übergeben Sie bei den Methoden Read, Write, GetPosition und SetPosition immer mit. Schließen Sie eine geöffnete Datei mit Close, sobald Sie sie nicht mehr benötigen.
Auf Nodes vom Typ FileType können Sie manuell über die Methoden ReadNode und CallMethod der Klasse OpcClient zugreifen. Alternativ bietet das SDK zahlreiche weitere Klassen, die den Zugriff auf solche Nodes unter anderem nach dem Vorbild von .NET umsetzen. Die NodeId legt fest, auf welchen Datei-Node der Client zugreift.
Die passende Klasse wählen
| Klasse | Vorbild in .NET | Geeignet für |
|---|---|---|
OpcFile | System. | ganze Inhalte in einem Aufruf lesen oder anhängen (ReadAllText, ReadAllLines, ReadAllBytes, AppendAllText, AppendAllLines) und Streams öffnen (Open, OpenRead, OpenWrite, OpenText, AppendText) |
OpcFileInfo (Namespace Opc.) | System. | Eigenschaften einer Datei abfragen (Exists, Length, Name, MimeType, CanWrite, CanUserWrite) und die Datei öffnen |
OpcFileStream | System. | Lesen, Schreiben und Positionieren über die Schnittstelle von Stream, auch zusammen mit StreamReader, StreamWriter oder CopyTo |
OpcFileMethods | keines | die Methoden des Datei-Nodes (Open, Read, Write, GetPosition, SetPosition, Close) einzeln aufrufen |
Den Modus beim Öffnen legt OpcFileMode fest: Read, Write, ReadWrite, EraseExisting und Truncate (Schreiben nach Leeren der Datei). Methoden zum Überschreiben einer ganzen Datei in einem Aufruf (wie File.WriteAllText) bietet OpcFile nicht. Zum Schreiben verwenden Sie einen mit OpenWrite oder Open geöffneten Stream.
Ganze Dateien lesen und schreiben
Gesamten Inhalt einer Textdatei lesen:
string reportText = OpcFile.ReadAllText(client, "ns=2;s=Machine/Report");Dim reportText As String = OpcFile.ReadAllText(client, "ns=2;s=Machine/Report")Weitere Textdaten an eine Textdatei anhängen:
OpcFile.AppendAllText(client, "ns=2;s=Machine/Report", "Lorem ipsum");OpcFile.AppendAllText(client, "ns=2;s=Machine/Report", "Lorem ipsum")Datei mit OpcFileStream öffnen und lesen:
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 UsingDatei mit OpcFileStream öffnen und schreiben:
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 UsingDen gesamten Inhalt als Zeilen oder als Bytes lesen:
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")Dateiinformationen abfragen und öffnen
Die Klasse OpcFileInfo des Namespace Opc.UaFx.Client beschreibt eine einzelne Datei. Auch der Namespace Opc.UaFx enthält eine Klasse OpcFileInfo. Die folgenden Beispiele geben den Typnamen deshalb voll qualifiziert an:
Instanz von OpcFileInfo erstellen:
// 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")Mit der Instanz von OpcFileInfo arbeiten:
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 IfEigenschaften abfragen und nur schreiben, wenn der Benutzer es darf: CanWrite gibt an, ob die Datei grundsätzlich beschreibbar ist. CanUserWrite gibt an, ob der angemeldete Benutzer sie beschreiben darf. Ein zum Schreiben geöffneter OpcFileStream berücksichtigt beides. Seine Eigenschaft CanWrite ist nur dann true, wenn beides zutrifft:
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 IfGroße Dateien als Stream verarbeiten
Große Dateien kopieren: Da OpcFileStream von Stream abgeleitet ist, kopieren Sie eine Datei des Servers mit CopyTo in eine lokale Datei. Der Stream liest den Inhalt dabei abschnittsweise:
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 UsingAn eine bestimmte Position schreiben: Mit Seek legen Sie die Position innerhalb der Datei fest, zum Beispiel ans Ende, um einen Eintrag anzuhängen:
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 UsingDateimethoden direkt aufrufen
Über das .NET-Konzept SafeHandle (Klasse 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 UsingÜber einen numerischen 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 TryNur Dateizugriffe über OpcFile, OpcFileInfo, OpcFileStream und SafeOpcFileHandle garantieren, dass eine geöffnete Datei auch dann freigegeben wird, wenn der Aufruf der Methode Close fehlt. Spätestens beim Schließen der Verbindung zum Server schließt der OpcClient dann alle geöffneten Dateien automatisch. Das gilt nicht, wenn Sie die Methoden der Klasse OpcFileMethods ohne das Präfix Secure verwenden.
Die OPC-UA-Spezifikation definiert keinen Weg, einen Node als Node vom Typ FileType und damit als Datei-Node zu erkennen. Das SDK kann einen Datei-Node deshalb anhand seiner Node-Struktur identifizieren:
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 IfFehler behandeln
Wenn der angegebene Node nicht existiert oder kein Datei-Node ist, lösen die Methoden von OpcFile, OpcFileInfo und OpcFileMethods eine InvalidOperationException aus. Wenn der Server einen Methodenaufruf ablehnt, löst die Methode eine OpcException mit dem Status des Servers aus. Das ist zum Beispiel der Fall, wenn der Benutzer die Datei nicht beschreiben darf oder die Datei bereits exklusiv geöffnet ist. Operationen, die der Modus des Streams nicht zulässt (zum Beispiel Schreiben in einen zum Lesen geöffneten Stream), quittiert OpcFileStream mit einer 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 TrySicherheit
Behandeln Sie Inhalte, die Sie von einem Server lesen, wie Eingaben von außen. Verwenden Sie zum Beispiel Dateinamen oder Pfade aus einer gelesenen Datei nicht ungeprüft für Zugriffe auf das lokale Dateisystem. Begrenzen Sie die Größe (Eigenschaft Length), bevor Sie eine Datei vollständig in den Speicher lesen. Prüfen Sie vor dem Schreiben die Eigenschaft CanUserWrite.
Abgrenzung
- Große Binärwerte, die ein Server nicht als Datei, sondern als Wert einer Variablen bereitstellt, liest die Klasse
OpcNodeStream(siehe Große Binärwerte als Stream). - Wie ein Server selbst Datei-Nodes bereitstellt, beschreibt die Seite Node-Typen im Server-Kapitel.

