Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Po otwarciu obiektu Package z funkcją <System.IO.FileAccess.ReadWrite?displayProperty=nameWithType> , a następnie otwórz skompresowaną część do odczytu, która nie została zmodyfikowana w bieżącej sesji, PackagePart.GetStream teraz zwraca strumień tylko do przodu zamiast wyszukiwanego MemoryStream.
Wersja wprowadzona
.NET 11 (wersja zapoznawcza 7)
Poprzednie zachowanie
Wcześniej po otwarciu elementu Package z elementem FileAccess.ReadWrite (który jest mapowany wewnętrznie na ZipArchiveMode.Update), otwarcie skompresowanej części do odczytu zwróciło możliwość wyszukiwania MemoryStream , która zawierała w pełni zdekompresowaną zawartość wpisu.
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
Nowe zachowanie
Począwszy od .NET 11, to samo wywołanie zwraca strumień tylko do przodu (bez możliwości wyszukiwania) dla skompresowanych części, które nie zostały zmodyfikowane w bieżącej sesji.
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)
Aby zaobserwować tę zmianę, wszystkie następujące warunki muszą być spełnione jednocześnie:
- Pakiet jest otwierany za pomocą
FileAccess.ReadWriteelementu (Package.Open(..., FileAccess.ReadWrite)). - Część jest otwierana tylko do odczytu (
GetStream(FileMode.Open, FileAccess.Read)). - Część jest kompresowana (
CompressionOptioninna niżNotCompressed). - Część nie została napisana ani zmodyfikowana wcześniej w tej samej sesji.
- Konsument bezwarunkowo szuka strumienia lub odczytuje
Position.
Nie ma to wpływu na następujące scenariusze:
- Pakiety tylko do odczytu (
FileAccess.Read): ich skompresowane strumienie części były już przekazywane tylko do przodu. - Nieskompresowane (
Stored) części: Pozostają one możliwe do poszukiwania. - Części zmodyfikowane wcześniej w bieżącej sesji: są one obsługiwane z migawki w pamięci, więc pozostają one dostępne do wyszukiwania.
- Uzyskiwanie
Stream.Lengthdostępu do elementu . - Odbiorcy tylko do przekazywania (typowy przypadek, taki jak
XmlReader,XDocument.Load, zestaw OPEN XML SDK iCopyTo). - Struktury docelowe wcześniejsze niż .NET 11: Optymalizacja jest bramowana za
NET11_0_OR_GREATER.
Typ zmiany przełamującej
Ta zmiana jest zmianą behawioralną.
Przyczyna zmiany
Wcześniej otwarcie skompresowanej części do odczytu z ReadWrite pakietu zawsze dekompresował cały wpis do elementu przed zwróceniem MemoryStream strumienia. Takie podejście wywołało strumień możliwy do wyszukiwania, ale narzuciło niepotrzebne alokacje pamięci i obciążenie procesora CPU dla typowego przypadku, w którym osoby wywołujące odczytują strumień sekwencyjnie (na przykład XmlReader lub zestaw OPEN XML SDK). Nowe zachowanie przesyła strumienie bezpośrednio z bazowego wpisu archiwum ZIP do odczytu tylko do przodu, co pozwala uniknąć dekompresji z góry.
Aby uzyskać więcej informacji, zobacz dotnet/runtime#129698.
Zalecana akcja
Jeśli kod wymaga możliwego do wyszukiwania strumienia ze skompresowanej części ReadWrite pakietu, skopiuj go ręcznie 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.
Alternatywnie, jeśli przypadek użycia nie wymaga ReadWrite dostępu do pakietu, otwórz go za pomocą FileAccess.Read polecenia . Pakiety tylko do odczytu zwróciły już strumienie tylko do przodu przed tą zmianą, więc ten tryb pozwala uniknąć niespodzianek dla kodu wrażliwego na wyszukiwanie.