考虑:
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
}
}
上面的代码会返回大型文件的内存不足异常,仅适用于小型文件。
答案 0 :(得分:12)
我认为仍然使用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
有一个像CopyTo
那样的Stream
方法,如果有的话,这实际上就是一个单行!)
答案 1 :(得分:1)
不要读取并一次读取并逐行读取它。如果您阅读结束,则立即将整个文件放入缓冲区。
答案 2 :(得分:-1)
试试这个:
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开销和存储所有内存的大量RAM消耗,将其全部转换为内存然后将其全部保存回来。
您可以随时调整缓冲区大小。
如果您希望旧方法在不抛出OutOfMemoryException
的情况下工作,则需要告诉垃圾收集器允许非常大的对象。
在App.config中,在<runtime>
下添加以下行(您的代码不需要它,但值得了解):
<gcAllowVeryLargeObjects enabled="true" />