Преобразование ANSI в UTF-8 & java.lang.OutOfMemoryError: пространство кучи Java - PullRequest
0 голосов
/ 14 мая 2018

Моя конечная цель - конвертировать файл из ANSI в UTF-8.Для этого я использую некоторый код с Java:

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class ConvertFromAnsiToUtf8 {

    public static void main(String[] args) throws IOException {

        try {
            Path p = Paths.get("C:\\shared_to_vm\\test_encode\\test.csv");
            ByteBuffer bb = ByteBuffer.wrap(Files.readAllBytes(p));
            CharBuffer cb = Charset.forName("windows-1252").decode(bb);
            bb = Charset.forName("UTF-8").encode(cb);
            Files.write(p, bb.array());
        } catch (Exception e) {
            System.out.println(e);
        } 

    } 

}

Код отлично работает, когда я тестирую его на небольших файлах.Мой файл конвертируется из ANSI в UTF-8, и все символы распознаются и хорошо кодируются.Но как только я пытаюсь использовать его в файле, который мне нужно преобразовать, я получаю сообщение об ошибке java.lang.OutOfMemoryError: пространство кучи Java.

Насколько я понимаю, я получил 1,5 миллиона строк в своем файле, так что я уверен, что создал слишком много объектов в своем приложении.

Конечно, я проверил, что означает эта ошибка и как я могу ее исправить (например, здесь или здесь ), но улучшается объем памяти моегоJVM единственный способ решить это?И если это так, сколько еще я должен использовать?

Любая помощь (совет, совет, ссылка или другое) будет принята с благодарностью!

Ответы [ 3 ]

0 голосов
/ 14 мая 2018

Если у вас большой файл, который больше, чем доступная память с произвольным доступом, вам следует преобразовывать символы по частям.

После вы можете найти пример:

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class Iconv {

    private static void iconv(Charset toCode, Charset fromCode, Path src, Path dst) throws IOException {
        CharsetDecoder decoder = fromCode.newDecoder();
        CharsetEncoder encoder = toCode.newEncoder();
        try (ReadableByteChannel source = FileChannel.open(src, StandardOpenOption.READ);
                WritableByteChannel destination = FileChannel.open(dst, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING,
                        StandardOpenOption.WRITE);) {
            ByteBuffer readBytes = ByteBuffer.allocate(4096);
            while (source.read(readBytes) > 0) {
                readBytes.flip();
                destination.write(encoder.encode(decoder.decode(readBytes)));
                readBytes.clear();
            }
        }
    }

    public static void main(String[] args) throws Exception {
        iconv(Charset.forName("UTF-8"), Charset.forName("Windows-1252"), Paths.get("test.csv") , Paths.get("test-utf8.csv") );
    }

}
0 голосов
/ 14 мая 2018

Потоковый ввод, преобразование кодировки символов и запись вывода по ходу.Таким образом, вам не нужно читать весь файл в память, а только столько, сколько вы хотите.

Если вы хотите минимизировать количество (медленных) системных вызовов, вы можете использовать аналогичный подход, но явно создать BufferedInputStream с большим внутренним буфером, а затем обернуть его в InputStreamReader.Но простой подход, показанный здесь, вряд ли будет критическим моментом во многих приложениях.

private static final Charset WINDOWS1252 = Charset.forName("windows-1252");

private static final int DEFAULT_BUF_SIZE = 8192;

public static void transcode(Path input, Path output) throws IOException {
    try (Reader r = Files.newBufferedReader(input, WINDOWS1252);
         Writer w = Files.newBufferedWriter(output, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW)) {
        char[] buf = new char[DEFAULT_BUF_SIZE];
        while (true) {
            int n = r.read(buf);
            if (n < 0) break;
            w.write(buf, 0, n);
        }
    }
}
0 голосов
/ 14 мая 2018

Не читать весь файл сразу:

ByteBuffer bb = ByteBuffer.wrap(Files.readAllBytes(p));

Вместо этого попробуйте читать построчно:

Files.lines(p, Charset.forName("windows-1252")).forEach(line -> {
   // Convert your line, write to file
});
...