Saya memiliki StreamReader
objek yang saya inisialisasi dengan aliran, sekarang saya ingin menyimpan aliran ini ke disk (aliran mungkin a .gif
atau .jpg
atau .pdf
).
Kode yang ada:
StreamReader sr = new StreamReader(myOtherObject.InputStream);
- Saya perlu menyimpan ini ke disk (saya memiliki nama file).
- Di masa depan saya mungkin ingin menyimpan ini ke SQL Server.
Saya memiliki tipe penyandian juga, yang akan saya perlukan jika saya menyimpannya ke SQL Server, benar?
Jawaban:
Seperti yang disorot oleh Tilendor dalam jawaban Jon Skeet, stream memiliki
CopyTo
metode sejak .NET 4.Atau dengan
using
sintaks:sumber
myOtherObject.InputStream.Seek(0, SeekOrigin.Begin)
jika Anda belum berada di awal atau Anda tidak akan menyalin seluruh aliran.Anda tidak boleh menggunakan
StreamReader
file biner (seperti gifs atau jpgs).StreamReader
adalah untuk data teks . Anda hampir pasti akan kehilangan data jika Anda menggunakannya untuk data biner sewenang-wenang. (Jika Anda menggunakan Encoding.GetEncoding (28591) Anda mungkin akan baik-baik saja, tapi apa gunanya?)Mengapa Anda perlu menggunakan
StreamReader
sama sekali? Mengapa tidak hanya menyimpan data biner sebagai data biner dan menulisnya kembali ke disk (atau SQL) sebagai data biner?EDIT: Karena ini tampaknya menjadi sesuatu yang orang ingin melihat ... jika Anda tidak hanya ingin menyalin satu aliran yang lain (misalnya untuk file) menggunakan sesuatu seperti ini:
Untuk menggunakannya untuk membuang aliran ke file, misalnya:
Catatan yang
Stream.CopyTo
diperkenalkan di .NET 4, pada dasarnya melayani tujuan yang sama.sumber
sumber
stream
objek diusing(){}
braket. Metode Anda tidak membuat aliran, jadi itu tidak boleh membuangnya.FileStream
sebagai gantinya, jika tidak maka akan tetap terbuka sampai sampah dikumpulkan.File.WriteAllBytes(destinationFilePath, input.ToArray());
. Dalam kasus saya,input
apakahMemoryStream
datang dari dalam aZipArchive
.sumber
File.WriteAllBytes(destinationFilePath, input.ToArray());
. Dalam kasus saya,input
apakahMemoryStream
datang dari dalam aZipArchive
.stream.Seek(0, SeekOrigin.Begin);
Saya tidak mendapatkan semua jawaban menggunakan
CopyTo
, di mana mungkin sistem yang menggunakan aplikasi mungkin belum ditingkatkan ke .NET 4.0+. Saya tahu beberapa orang ingin memaksa orang untuk melakukan upgrade, tetapi kompatibilitasnya juga bagus.Hal lain, saya tidak bisa menggunakan aliran untuk menyalin dari aliran lain di tempat pertama. Mengapa tidak lakukan saja:
Setelah Anda memiliki byte, Anda dapat dengan mudah menuliskannya ke file:
Kode ini berfungsi saat saya mengujinya dengan a
.jpg
file, meskipun saya akui saya hanya menggunakannya dengan file kecil (kurang dari 1 MB). Satu aliran, tidak ada penyalinan antar aliran, tidak perlu penyandian, cukup tulis byte! Tidak perlu terlalu rumit hal-hal denganStreamReader
jika Anda sudah memiliki aliran Anda dapat mengonversibytes
secara langsung dengan.ToArray()
!Hanya kerugian potensial yang dapat saya lihat dengan melakukannya dengan cara ini adalah jika ada file besar yang Anda miliki, menjadikannya sebagai stream dan menggunakan
.CopyTo()
atau setara memungkinkanFileStream
untuk streaming itu daripada menggunakan array byte dan membaca byte satu per satu. Mungkin lebih lambat melakukannya dengan cara ini, sebagai hasilnya. Tetapi seharusnya tidak tersedak karena.Write()
metodeFileStream
pegangan menulis byte, dan itu hanya melakukannya satu byte pada satu waktu, sehingga tidak akan menyumbat memori, kecuali bahwa Anda harus memiliki cukup memori untuk menahan aliran sebagaibyte[]
objek . Dalam situasi saya di mana saya menggunakan ini, mendapatkanOracleBlob
, saya harus pergi kebyte[]
, itu cukup kecil, dan lagi pula, tidak ada streaming yang tersedia untuk saya, jadi saya hanya mengirim byte saya ke fungsi saya, di atas.Pilihan lain, menggunakan aliran, akan menggunakannya dengan
CopyStream
fungsi Jon Skeet yang ada di pos lain - ini hanya menggunakanFileStream
untuk mengambil aliran input dan membuat file dari itu secara langsung. Itu tidak digunakanFile.Create
, seperti yang dia lakukan (yang awalnya tampak bermasalah bagi saya, tetapi kemudian menemukan itu kemungkinan hanya bug VS ...).sumber
Close
karenausing()
inputStream.Close()
, lihat lagi -inputStream
dikirim sebagai variabel. Adausing
padapath+filename
aliran output. Jika Anda berbicara tentangfs.Close()
di tengah-tengahusing
, maaf, Anda benar tentang itu dan saya menghapusnya.sumber
Mengapa tidak menggunakan objek FileStream?
sumber
byte[]
, saya pikir itu akan jarang bahwa Anda akan streaming 1 GB + gumpalan ke file ... kecuali jika Anda memiliki situs yang menyimpan DVD torrents ... Plus , kebanyakan komputer memiliki setidaknya 2 GB RAM yang tersedia hari ini, toh ... Peringatan itu valid, tapi saya pikir ini adalah kasus di mana itu mungkin "cukup baik" untuk sebagian besar pekerjaan.Pilihan lain adalah untuk mendapatkan aliran ke
byte[]
dan gunakanFile.WriteAllBytes
. Ini harus dilakukan:Membungkusnya dengan metode ekstensi memberikan penamaan yang lebih baik:
sumber
sumber
FileStream
- nice!Berikut adalah contoh yang menggunakan penggunaan yang tepat dan implementasi idisposable:
... dan ada juga ini
Kuncinya adalah memahami penggunaan yang tepat dari penggunaan (yang harus diimplementasikan pada instantiasi objek yang mengimplementasikan idisposable seperti yang ditunjukkan di atas), dan memiliki ide yang bagus tentang bagaimana properti bekerja untuk stream. Posisi secara harfiah adalah indeks dalam aliran (yang dimulai dari 0) yang diikuti setiap byte dibaca menggunakan metode readbyte. Dalam hal ini saya pada dasarnya menggunakannya sebagai pengganti variabel loop dan hanya membiarkannya mengikuti sampai ke panjang yang pada akhirnya adalah akhir dari seluruh aliran (dalam byte). Abaikan dalam byte karena praktis sama dan Anda akan memiliki sesuatu yang sederhana dan elegan seperti ini yang menyelesaikan semuanya dengan bersih.
Perlu diingat juga, bahwa metode ReadByte hanya membuang byte ke int dalam proses dan hanya dapat dikonversi kembali.
Saya akan menambahkan implementasi lain yang baru-baru ini saya tulis untuk membuat semacam buffer dinamis untuk memastikan data berurutan menulis untuk mencegah kelebihan besar
Penjelasannya cukup sederhana: kita tahu bahwa kita perlu mengingat seluruh rangkaian data yang ingin kita tulis dan juga kita hanya ingin menulis jumlah tertentu, jadi kita ingin loop pertama dengan parameter terakhir kosong (sama seperti saat ). Selanjutnya, kita menginisialisasi buffer array byte yang diatur ke ukuran yang dilewati, dan dengan loop kedua kita membandingkan j dengan ukuran buffer dan ukuran yang asli, dan jika itu lebih besar dari ukuran aslinya array byte, akhiri prosesnya.
sumber