如何将大文件(> 1 GB)的编码转换为Windows 1252而不会出现内存不足exception?

考虑:

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 } } 

上面的代码返回大文件的内存不足exception,仅适用于小型文件。

我认为仍然使用StreamReaderStreamWriter但是读取字符块而不是一次性或逐行读取是最优雅的解决方案。 它不会随意假设文件由可管理长度的行组成,并且它也不会破坏多字节字符编码。

 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有一个类似StreamCopyTo方法,如果有的话,这本质上就是一个单行!)

不要readToEnd并逐行读取或一次读取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开销和存储所有内存的大量RAM消耗,将其全部转换为内存然后将其全部保存回来。

您始终可以调整缓冲区大小。

如果您希望旧方法在不抛出OutOfMemoryException情况下工作,则需要告知垃圾收集器允许非常大的对象。

在App.config中,在添加以下行(您的代码不需要它,但值得了解):