PackagePart.GetStream() gibt einen nicht suchbaren Datenstrom für komprimierte Teile in ReadWrite-Paketen zurück.

Wenn Sie eine Package mit System.IO.FileAccess.ReadWrite?displayProperty=nameWithType> öffnen und dann einen komprimierten Teil zum Lesen öffnen, der in der aktuellen Sitzung nicht geändert wurde, PackagePart.GetStream wird nun anstelle eines suchbaren MemoryStreamDatenstroms ein Vorwärtsdatenstrom <zurückgegeben.

Eingeführt in Version

.NET 11 Vorschau 7

Bisheriges Verhalten

Wenn Sie zuvor eine Package Verbindung ( FileAccess.ReadWrite die intern ZipArchiveMode.Updatezugeordnet ist) geöffnet haben, wurde beim Öffnen eines komprimierten Teils zum Lesen ein suchbarer MemoryStream Teil zurückgegeben, der den vollständig dekomprimierten Eintragsinhalt enthielt.

using Package package = Package.Open("file.docx", FileMode.Open, FileAccess.ReadWrite);
PackagePart part = package.GetPart(new Uri("/word/document.xml", UriKind.Relative));

// Returned a seekable MemoryStream.
using Stream stream = part.GetStream(FileMode.Open, FileAccess.Read);
Console.WriteLine(stream.CanSeek);   // true
stream.Seek(0, SeekOrigin.Begin);    // succeeded
Console.WriteLine(stream.Position);  // 0

Neues Verhalten

Ab .NET 11 gibt derselbe Aufruf einen vorwärtsgerichteten (nicht suchbaren) Datenstrom für komprimierte Teile zurück, die in der aktuellen Sitzung nicht geändert wurden.

using Package package = Package.Open("file.docx", FileMode.Open, FileAccess.ReadWrite);
PackagePart part = package.GetPart(new Uri("/word/document.xml", UriKind.Relative));

// Returns a forward-only (non-seekable) stream.
using Stream stream = part.GetStream(FileMode.Open, FileAccess.Read);
Console.WriteLine(stream.CanSeek);   // false
stream.Seek(0, SeekOrigin.Begin);    // throws NotSupportedException
stream.Position = 0;                 // throws NotSupportedException
Console.WriteLine(stream.Length);    // still works (reported from entry metadata)

Alle folgenden Bedingungen müssen gleichzeitig erfüllt sein, damit Sie diese Änderung beobachten können:

  • Das Paket wird mit FileAccess.ReadWrite (Package.Open(..., FileAccess.ReadWrite)) geöffnet.
  • Der Teil wird nur zum Lesen (GetStream(FileMode.Open, FileAccess.Read)) geöffnet.
  • Der Teil wird komprimiert (CompressionOption außer NotCompressed).
  • Der Teil wurde in derselben Sitzung nicht geschrieben oder geändert.
  • Der Verbraucher sucht bedingungslos Positionden Datenstrom oder liest .

Die folgenden Szenarien sind nicht betroffen:

  • Schreibgeschützte Pakete (FileAccess.Read): Ihre komprimierten Teildatenströme waren bereits vorwärts.
  • Nicht komprimierte (Stored) Teile: Sie bleiben suchbar.
  • Teile, die weiter oben in der aktuellen Sitzung geändert wurden: Sie werden aus einer Speichermomentaufnahme bereitgestellt, sodass sie suchbar bleiben.
  • Zugreifen auf Stream.Length.
  • Forward-only-Consumer (der gängige Fall, z XmlReader. B. , XDocument.Loaddas Open XML SDK und CopyTo).
  • Zielframeworks vor .NET 11: Die Optimierung wird hinter NET11_0_OR_GREATERdas Ziel verschoben.

Art der einschneidenden Änderung

Diese Änderung ist eine Verhaltensänderung.

Grund für die Änderung

Zuvor hat das Öffnen eines komprimierten Teils zum Lesen aus einem ReadWrite Paket den gesamten Eintrag MemoryStream immer dekomprimiert, bevor er den Datenstrom zurückgibt. Dieser Ansatz erzeugte einen suchbaren Datenstrom, hat jedoch unnötige Speicherzuweisungen und CPU-Aufwand für den allgemeinen Fall auferlegt, in dem Aufrufer den Datenstrom nur sequenziell lesen (z XmlReader . B. das Open XML SDK). Das neue Verhalten streamt direkt aus dem zugrunde liegenden ZIP-Archiveintrag für Vorwärtslesevorgänge, wodurch die Vor-Front-Dekomprimierung vermieden wird.

Weitere Informationen finden Sie unter dotnet/runtime#129698.

Wenn Ihr Code einen suchbaren Datenstrom aus einem komprimierten Teil eines ReadWrite Pakets erfordert, kopieren Sie ihn manuell in folgendes MemoryStream :

using Stream partStream = part.GetStream(FileMode.Open, FileAccess.Read);
using MemoryStream seekable = new();
partStream.CopyTo(seekable);
seekable.Position = 0;
// Use 'seekable'. It's fully buffered and seekable.

Wenn Ihr Anwendungsfall keinen Zugriff auf das Paket erfordert ReadWrite , öffnen Sie ihn stattdessen mit FileAccess.Read . Schreibgeschützte Pakete haben bereits forward-only Streams vor dieser Änderung zurückgegeben, sodass dieser Modus keine Überraschungen für suchabhängigen Code verhindert.

Betroffene APIs