Đây là câu trả lời của dnewcome trong StreamReader tùy chỉnh. Nó chỉ đơn giản bao bọc một trình đọc luồng thực và thay thế các ký tự khi chúng được đọc.
Tôi chỉ thực hiện một số phương pháp để tiết kiệm thời gian cho mình. Tôi đã sử dụng điều này kết hợp với XDocument.Load và một dòng tệp và chỉ phương thức Read (char [] buffer, int index, int count) được gọi, vì vậy nó hoạt động như thế này. Bạn có thể cần triển khai các phương pháp bổ sung để điều này hoạt động cho ứng dụng của bạn. Tôi đã sử dụng phương pháp này vì nó có vẻ hiệu quả hơn các câu trả lời khác. Tôi cũng chỉ triển khai một trong các hàm tạo, bạn rõ ràng có thể triển khai bất kỳ hàm tạo nào trong số các hàm tạo StreamReader mà bạn cần, vì nó chỉ là một chuyển qua.
Tôi đã chọn thay thế các ký tự hơn là loại bỏ chúng bởi vì nó đơn giản hóa giải pháp. Bằng cách này, độ dài của văn bản được giữ nguyên, do đó không cần theo dõi một chỉ mục riêng biệt.
public class InvalidXmlCharacterReplacingStreamReader : TextReader
{
private StreamReader implementingStreamReader;
private char replacementCharacter;
public InvalidXmlCharacterReplacingStreamReader(Stream stream, char replacementCharacter)
{
implementingStreamReader = new StreamReader(stream);
this.replacementCharacter = replacementCharacter;
}
public override void Close()
{
implementingStreamReader.Close();
}
public override ObjRef CreateObjRef(Type requestedType)
{
return implementingStreamReader.CreateObjRef(requestedType);
}
public void Dispose()
{
implementingStreamReader.Dispose();
}
public override bool Equals(object obj)
{
return implementingStreamReader.Equals(obj);
}
public override int GetHashCode()
{
return implementingStreamReader.GetHashCode();
}
public override object InitializeLifetimeService()
{
return implementingStreamReader.InitializeLifetimeService();
}
public override int Peek()
{
int ch = implementingStreamReader.Peek();
if (ch != -1)
{
if (
(ch < 0x0020 || ch > 0xD7FF) &&
(ch < 0xE000 || ch > 0xFFFD) &&
ch != 0x0009 &&
ch != 0x000A &&
ch != 0x000D
)
{
return replacementCharacter;
}
}
return ch;
}
public override int Read()
{
int ch = implementingStreamReader.Read();
if (ch != -1)
{
if (
(ch < 0x0020 || ch > 0xD7FF) &&
(ch < 0xE000 || ch > 0xFFFD) &&
ch != 0x0009 &&
ch != 0x000A &&
ch != 0x000D
)
{
return replacementCharacter;
}
}
return ch;
}
public override int Read(char[] buffer, int index, int count)
{
int readCount = implementingStreamReader.Read(buffer, index, count);
for (int i = index; i < readCount+index; i++)
{
char ch = buffer[i];
if (
(ch < 0x0020 || ch > 0xD7FF) &&
(ch < 0xE000 || ch > 0xFFFD) &&
ch != 0x0009 &&
ch != 0x000A &&
ch != 0x000D
)
{
buffer[i] = replacementCharacter;
}
}
return readCount;
}
public override Task<int> ReadAsync(char[] buffer, int index, int count)
{
throw new NotImplementedException();
}
public override int ReadBlock(char[] buffer, int index, int count)
{
throw new NotImplementedException();
}
public override Task<int> ReadBlockAsync(char[] buffer, int index, int count)
{
throw new NotImplementedException();
}
public override string ReadLine()
{
throw new NotImplementedException();
}
public override Task<string> ReadLineAsync()
{
throw new NotImplementedException();
}
public override string ReadToEnd()
{
throw new NotImplementedException();
}
public override Task<string> ReadToEndAsync()
{
throw new NotImplementedException();
}
public override string ToString()
{
return implementingStreamReader.ToString();
}
}