考虑:
public static void ConvertFileToUnicode1252(string filePath, Encoding srcEncoding)
{
try
{
StreamReader fileStream = new StreamReader(filePath);
Encoding targetEncoding = Encoding.GetEncoding(1252);
string fileContent = fileStream.ReadToEnd();
fileStream.Close();
// Saving file as ANSI 1252
Byte[] srcBytes = srcEncoding.GetBytes(fileContent);
Byte[] ansiBytes = Encoding.Convert(srcEncoding, targetEncoding, srcBytes);
string ansiContent = targetEncoding.GetString(ansiBytes);
// Now writes contents to file again
StreamWriter ansiWriter = new StreamWriter(filePath, false);
ansiWriter.Write(ansiContent);
ansiWriter.Close();
//TODO -- log success details
}
catch (Exception e)
{
throw e;
// TODO -- log failure details
}
}
上面的代码返回大型文件的删除异常,仅适用于小型文件。
我认为仍使用 StreamReader
和 StreamWriter
,但是读取字符的块而不是一行或行划分是最优雅的解决方案。它不会任意假设该文件由可管理长度的行组成,并且也不会与多字节字符编码中断。
public static void ConvertFileEncoding(string srcFile, Encoding srcEncoding, string destFile, Encoding destEncoding)
{
using (var reader = new StreamReader(srcFile, srcEncoding))
using (var writer = new StreamWriter(destFile, false, destEncoding))
{
char[] buf = new char[4096];
while (true)
{
int count = reader.Read(buf, 0, buf.Length);
if (count == 0)
break;
writer.Write(buf, 0, count);
}
}
}
(我希望StreamReader
像Stream
一样具有CopyTo
方法,如果有的话,这本质上是一个单线!)
不要一次阅读并像线或x字符一样读取它。如果您阅读要结束,则将整个文件一次放入缓冲区。
尝试以下:
using (FileStream fileStream = new FileStream(filePath, FileMode.Open))
{
int size = 4096;
Encoding targetEncoding = Encoding.GetEncoding(1252);
byte[] byteData = new byte[size];
using (FileStream outputStream = new FileStream(outputFilepath, FileMode.Create))
{
int byteCounter = 0;
do
{
byteCounter = fileStream.Read(byteData, 0, size);
// Convert the 4k buffer
byteData = Encoding.Convert(srcEncoding, targetEncoding, byteData);
if (byteCounter > 0)
{
outputStream.Write(byteData, 0, byteCounter);
}
}
while (byteCounter > 0);
inputStream.Close();
}
}
我从内存中完成了一些语法错误,但这就是我使用大文件的方式,一次在块中阅读,进行一些处理并保存块。这实际上是唯一的方法(流),而无需依靠大量的io读取所有内容的开销和大量存储所有内容,将其全部转换为内存,然后将其全部保存。
您始终可以调整缓冲区大小。
如果您希望旧方法在不扔OutOfMemoryException
的情况下工作,则需要告诉垃圾收集器允许非常大的对象。
在app.config中,在<runtime>
下添加以下行(您不需要我的代码,但值得知道):
<gcAllowVeryLargeObjects enabled="true" />