URL Asli: http://www.blogwind.com/Wuvist/42999.shtml
Dalam kerangka .Net, pengkodean yang digunakan oleh StreamReader harus ditentukan dalam konstruktor dan tidak dapat diubah sama sekali di tengah jalan.
Dalam keadaan normal, hal ini tidak akan menimbulkan masalah. Secara umum, jika suatu file dibaca dari hard disk, pengkodean dalam satu file umumnya seragam. Bahkan jika Anda menemukan kesalahan pembacaan, Anda dapat menutup StreamReader dan memulai kembali pembacaan menggunakan pengkodean baru.
Saya baru-baru ini mengalami kebutuhan untuk mengubah pengkodean, dan program saya tidak mematikan kesempatan untuk membaca ulang. Karena BaseStream dari StreamReader yang saya gunakan adalah Network Stream, saya tidak dapat menutupnya... tetapi hal-hal yang melewati Network Stream mungkin berisi pengkodean yang berbeda... GB2312, Big5, UTF8, ISO-8859-1, dll. .. Meskipun informasi pengkodean diperoleh terlebih dahulu, dan kemudian konten spesifik dibaca. Namun, jika pengkodean Stream Reader yang digunakan di awal salah, konten yang dibaca tidak akan pernah dapat dipulihkan... kata-kata akan hilang...
I tidak bisa mendapatkannya lagi... Setelah menyandikan informasi, buat kembali Stream Reader baru, karena konten tertentu telah di-buffer oleh Stream Reader asli...
Satu-satunya solusi adalah dengan mengimplementasikan Stream Reader yang dapat mengubah Atribut CurrentEncoding...
Tulis semuanya dari awal Awalnya sangat tidak praktis. Saya pertama kali mendapatkan kode sumber mono dan membuat modifikasi dari kode implementasi Stream Reader mono.
Stream Reader sebenarnya sangat sederhana. Ia memiliki dua buffer di dalamnya, satu adalah buffer input dan yang lainnya adalah buffer yang didekodekan. Yang pertama digunakan untuk menyimpan data asli yang dibaca dari aliran dasar, dan yang terakhir digunakan untuk menyimpan cache diterjemahkan sesuai dengan data asli... ...Selama Anda memahami metode ReadBuffer dalam implementasi mono, tidak terlalu sulit untuk memodifikasi CurrentEncoding secara dinamis...
Protokol jaringan yang perlu saya tangani adalah protokol garis ...Saya hanya memanggil metode Readline dari StreamReader dalam program, tetapi sepenuhnya Kedua metode Baca tidak digunakan, yang juga memudahkan saya untuk mengubah pengkodean secara dinamis...
Apa yang saya lakukan adalah setiap kali saya panggil Readline, saya tidak hanya memindahkan kursor (pos) dari buffer yang didekode, tetapi juga memindahkan kursor baru di buffer input (pos_input), metodenya sangat sederhana temukan simbol baris baru... Saya menambahkan satu baris lagi ke metode FindNextEOL:
int TemukanBerikutnyaEOL()
{
TemukanInputBerikutnyaEOL();
....
Fungsi baru FindNextInputEOL adalah replika lengkap dari FindNextEOL, kecuali fungsi pertama memproses buffer input, sedangkan fungsi kedua memproses buffer yang didekodekan...
Dengan cara ini, saya dapat mengetahui bahwa setelah setiap Readline, buffer input memiliki belum didekodekan oleh lapisan atas. Apa data asli yang dibaca...
Kemudian, tambahkan metode Set ke atribut CurrentEncoding:
mengatur
{
pengkodean=nilai;
decoder = pengkodean.GetDecoder();
decode_count = pos + decoder.GetChars (input_buffer, pos_input, cbEncoded, pos_input, decode_buffer, pos);
}
Saat mengatur pengkodean baru, program akan mendekode ulang data asli yang belum dibaca sesuai dengan kursor buffer input (pos_input), dan mengganti konten dalam buffer yang didekodekan.
Kemudian, semuanya selesai... Anda bahkan tidak perlu melakukan modifikasi apa pun pada metode Readline... Kecuali untuk memasukkan variabel cbEncoded ke dalam global...
Namun, modifikasi ini membuat kedua metode Read sama sekali tidak dapat digunakan ... Setelah dipanggil... itu akan menyebabkan dua kursor di buffer input dan buffer yang didekode menjadi tidak sinkron... Kode lengkap terlampir di bawah ini ...Terima kasih sebelumnya…
/
// Sistem.IO.StreamReader.cs
//
// Pengarang:
// Dietmar Maurer ( [email protected] )
// Miguel de Icaza ( [email protected] )
//
// (C) Ximian, Inc.http ://www.ximian.com
// Hak Cipta (C) 2004 Novell ( http://www.novell.com )
//
//
// Hak Cipta (C) 2004 Novell, Inc ( http://www.novell.com )
//
// Izin dengan ini diberikan, tanpa dipungut biaya, kepada siapa pun yang memperolehnya
// salinan perangkat lunak ini dan file dokumentasi terkait (file
// "Perangkat Lunak"), untuk menangani Perangkat Lunak tanpa batasan, termasuk
// tanpa batasan hak untuk menggunakan, menyalin, memodifikasi, menggabungkan, menerbitkan,
// mendistribusikan, mensublisensikan, dan/atau menjual salinan Perangkat Lunak, dan kepada
// mengizinkan orang yang menerima Perangkat Lunak untuk melakukan hal tersebut, dengan tunduk pada
// kondisi berikut:
//
// Pemberitahuan hak cipta di atas dan pemberitahuan izin ini adalah
// disertakan dalam semua salinan atau sebagian besar Perangkat Lunak.
//
// PERANGKAT LUNAK DISEDIAKAN "APA ADANYA", TANPA JAMINAN APA PUN,
// TERSURAT MAUPUN TERSIRAT, TERMASUK NAMUN TIDAK TERBATAS PADA JAMINAN
// KELAYAKAN UNTUK DIPERDAGANGKAN, KESESUAIAN UNTUK TUJUAN TERTENTU DAN
// TIDAK ADA PELANGGARAN. DALAM HAL APA PUN PENULIS ATAU PEMEGANG HAK CIPTA
// BERTANGGUNG JAWAB ATAS KLAIM, KERUSAKAN ATAU TANGGUNG JAWAB LAINNYA, BAIK DALAM SUATU TINDAKAN
// KONTRAK, HUKUM ATAU LAINNYA, YANG TIMBUL DARI, LUAR ATAU DALAM HUBUNGAN
// DENGAN PERANGKAT LUNAK ATAU PENGGUNAAN ATAU HAL-HAL LAIN DALAM PERANGKAT LUNAK.
//
menggunakan Sistem;
menggunakan Sistem.Teks;
menggunakan System.Runtime.InteropServices;
namespace System.IO
{
[Dapat diserialkan]
kelas publik DynamicStreamReader : TextReader
{
const int DefaultBufferSize = 1024;
const int DefaultFileBufferSize = 4096;
const int UkuranBuffer Minimum = 128;
//
//Buffer masukan
//
byte[] masukan_buffer;
//
// Buffer yang didekodekan dari buffer input di atas
//
karakter [] dikodekan_buffer;
//
// Byte yang didekodekan dalam decode_buffer.
//
int decode_count;
//
// Posisi saat ini di decode_buffer
//
ke dalam pos;
//
// Posisi saat ini di input_buffer
//
int masukan_pos;
//
// Ukuran buffer yang kita gunakan
//
int ukuran_buffer;
int lakukan_pemeriksaan;
Pengkodean pengkodean;
Dekoder dekoder;
aliran base_stream;
bool mayBlock;
StringBuilder line_builder;
kelas privat NullStreamReader : DynamicStreamReader
{
penggantian publik ke Peek ()
{
kembali -1;
}
penggantian publik int Baca ()
{
kembali -1;
}
public override int Baca ([Masuk, Keluar] char[] buffer, int indeks, int count)
{
kembali 0;
}
string penggantian publik ReadLine ()
{
kembalikan nol;
}
string penggantian publik ReadToEnd ()
{
return String.Kosong;
}
penggantian publik Stream BaseStream
{
dapatkan { return Stream.Null }
}
penggantian publik Pengkodean Pengkodean Saat Ini
{
dapatkan { return Encoding.Unicode }
}
}
public new static readonly DynamicStreamReader Null = (DynamicStreamReader)(new NullStreamReader());
DynamicStreamReader internal() {}
DynamicStreamReader publik(Aliran aliran)
: ini (stream, Encoding.UTF8, true, DefaultBufferSize) { }
public DynamicStreamReader(Stream stream, bool detector_encoding_from_bytemarks)
: ini (aliran, Encoding.UTF8, deteksi_encoding_from_bytemarks, DefaultBufferSize) { }
public DynamicStreamReader(Aliran aliran, Pengkodean pengkodean)
: ini (aliran, penyandian, true, DefaultBufferSize) { }
public DynamicStreamReader(Aliran aliran, Pengkodean penyandian, bool detector_encoding_from_bytemarks)
: ini (aliran, penyandian, deteksi_encoding_from_bytemarks, DefaultBufferSize) { }
DynamicStreamReader publik(Aliran aliran, Pengkodean pengkodean, bool deteksi_encoding_from_bytemarks, int buffer_size)
{
Inisialisasi (streaming, pengkodean, deteksi_encoding_from_bytemarks, buffer_size);
}
DynamicStreamReader publik (jalur string)
: ini (jalur, Encoding.UTF8, true, DefaultFileBufferSize) { }
public DynamicStreamReader(jalur string, bool detector_encoding_from_bytemarks)
: ini (jalur, Encoding.UTF8,deteksi_encoding_from_bytemarks, DefaultFileBufferSize) { }
public DynamicStreamReader(jalur string, Pengkodean pengkodean)
: ini (jalur, penyandian, true, DefaultFileBufferSize) { }
public DynamicStreamReader(jalur string, Pengkodean penyandian, bool detector_encoding_from_bytemarks)
: ini (jalur, pengkodean, deteksi_encoding_from_bytemarks, DefaultFileBufferSize) { }
DynamicStreamReader publik (jalur string, pengkodean pengkodean, bool deteksi_encoding_from_bytemarks, int buffer_size)
{
jika (null == jalur)
melempar ArgumentNullException baru("jalur");
if (String.Kosong == jalur)
throw new ArgumentException("Jalur kosong tidak diperbolehkan");
jika (jalur.IndexOfAny (Jalur.InvalidPathChars) != -1)
throw new ArgumentException("jalur berisi karakter tidak valid");
jika (null == pengkodean)
melempar ArgumentNullException baru ("pengkodean");
jika (ukuran_buffer <= 0)
throw new ArgumentOutOfRangeException ("buffer_size", "Ukuran minimum buffer harus positif");
string DirName = Path.GetDirectoryName(path);
if (DirName != String.Empty && !Directory.Exists(DirName))
throw new DirectoryNotFoundException ("Direktori '" + DirName + "' tidak ditemukan.");
if (!File.Exists(path))
throw new FileNotFoundException("File tidak ditemukan.", jalur);
Aliran aliran = (Aliran) File.OpenRead (jalur);
Inisialisasi (streaming, pengkodean, deteksi_encoding_from_bytemarks, buffer_size);
}
kekosongan internal Inisialisasi (Aliran aliran, Pengkodean pengkodean, bool deteksi_encoding_from_bytemarks, int buffer_size)
{
jika (null == aliran)
melempar ArgumentNullException baru ("aliran");
jika (null == pengkodean)
melempar ArgumentNullException baru ("pengkodean");
jika (!stream.CanRead)
throw new ArgumentException ("Tidak dapat membaca streaming");
jika (ukuran_buffer <= 0)
throw new ArgumentOutOfRangeException ("buffer_size", "Ukuran minimum buffer harus positif")
;
buffer_size = MinimumBufferSize;
base_stream = aliran;
input_buffer = byte baru [buffer_size];
this.buffer_size = buffer_size;
this.encoding = pengkodean;
decoder = pengkodean.GetDecoder();
byte [] pembukaan = pengkodean.GetPreamble();
do_checks = deteksi_encoding_from_bytemarks ?
do_checks += (pembukaan.Panjang == 0) ?
decode_buffer = karakter baru [encoding.GetMaxCharCount (buffer_size)];
decode_count = 0;
pos = 0;
masukan_pos =0;
}
Aliran Dasar Aliran virtual publik
{
mendapatkan
{
kembalikan base_stream;
}
}
Pengkodean virtual publik Pengkodean Saat Ini
{
mendapatkan
{
jika (pengkodean == null)
melempar Pengecualian baru();
mengembalikan pengkodean;
}
mengatur
{
pengkodean=nilai;
decoder = pengkodean.GetDecoder();
decode_count = pos + decoder.GetChars (input_buffer, pos_input, cbEncoded - pos_input, decode_buffer, pos);
//BuangBufferedData();
}
}
penggantian publik batal Tutup ()
{
Buang(benar);
}
protected override void Buang (bool membuang)
{
if (membuang && base_stream != null)
base_stream.Tutup();
input_buffer = nol;
decode_buffer = nol;
pengkodean = nol;
dekoder = nol;
base_stream = nol;
base.Dispose (membuang);
}
//
// Menyediakan deteksi otomatis pengkodean, serta melompati
// tanda byte di awal aliran.
//
int DoChecks (jumlah int)
{
jika ((lakukan_periksa & 2) == 2)
{
byte [] pembukaan = pengkodean.GetPreamble();
int c = pembukaan.Panjang;
jika (hitung >= c)
{
ke dalam aku;
untuk (saya = 0; saya < c; saya++)
jika (input_buffer [i] != pembukaan [i])
istirahat;
jika (saya == c)
kembalikan saya;
}
}
jika ((lakukan_periksa & 1) == 1)
{
jika (hitung < 2)
kembalikan 0;
jika (input_buffer [0] == 0xfe && input_buffer [1] == 0xff)
{
this.encoding = Pengkodean.BigEndianUnicode;
kembali 2;
}
jika (input_buffer [0] == 0xff && input_buffer [1] == 0xfe)
{
this.encoding = Pengkodean.Unicode;
kembali 2;
}
jika (hitung < 3)
kembalikan 0;
jika (input_buffer [0] == 0xef && input_buffer [1] == 0xbb && input_buffer [2] == 0xbf)
{
this.encoding = Pengkodean.UTF8;
kembali 3;
}
}
kembalikan 0;
}
kekosongan publik DiscardBufferedData ()
{
pos = decode_count = 0;
mayBlock = salah;
// Buang juga status internal dekoder.
decoder = pengkodean.GetDecoder();
}
int cbDikodekan;
int parse_start;
// buffernya kosong, isi lagi
int pribadi ReadBuffer ()
{
pos = 0;
masukan_pos = 0;
cbEncoded = 0;
// terus mengulang hingga decoder memberi kita beberapa karakter
decode_count = 0;
parse_start = 0;
Mengerjakan
{
cbEncoded = base_stream.Read (input_buffer, 0, buffer_size);
jika (cbDikodekan == 0)
kembali 0;
mayBlock = (cbEncoded <buffer_size);
jika (lakukan_periksa > 0)
{
Pengkodean lama = pengkodean;
parse_start = DoChecks (cbEncoded);
jika (lama! = pengkodean)
{
decoder = pengkodean.GetDecoder();
}
lakukan_pemeriksaan = 0;
cbDikodekan -= parse_start;
}
decode_count += decoder.GetChars (input_buffer, parse_start, cbEncoded, decode_buffer, 0);
parse_start = 0;
} while (jumlah_dekode == 0);
kembalikan jumlah_dekode;
}
penggantian publik ke Intip ()
{
jika (base_stream == nol)
throw new ObjectDisposeException ("StreamReader", "Tidak dapat membaca dari StreamReader yang tertutup");
jika (pos >= decode_count && (mayBlock || ReadBuffer () == 0))
kembali -1;
kembalikan decode_buffer [pos];
}
penggantian publik int Baca ()
{
throw new Exception("Pembaca Dinamis tidak dapat membaca!");
}
public override int Baca ([Masuk, Keluar] char[] dest_buffer, int indeks, int count)
{
throw new Exception("Pembaca Dinamis tidak dapat membaca!");
}
bool ditemukanCR_input;
int TemukanInputBerikutnyaEOL()
{
karakter c = '