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



考虑:

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

上面的代码返回大型文件的删除异常,仅适用于小型文件。

我认为仍使用 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);
        }
    }
}

(我希望StreamReaderStream一样具有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" />

相关内容

  • 没有找到相关文章

最新更新