我的最终目标是将文件从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堆空间。
据我所知,我的文件中有150万行,所以我很确定我用我的应用程序创建了太多的对象。
当然,我已经检查了这个错误意味着什么以及如何解决它(例如here或here)但是提高我的JVM的内存容量是解决它的唯一方法?如果是的话,我还应该使用多少?
任何形式的帮助(提示,建议,链接或其他)将不胜感激!
答案 0 :(得分:0)
不要一次阅读整个文件:
ByteBuffer bb = ByteBuffer.wrap(Files.readAllBytes(p));
相反,尝试逐行阅读:
Files.lines(p, Charset.forName("windows-1252")).forEach(line -> {
// Convert your line, write to file
});
答案 1 :(得分:0)
如果你有一个大的文件,比可用的随机存取内存大,你应该逐块转换字符。
您可以找到以下示例:
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") );
}
}
答案 2 :(得分:0)
流式输入,转换字符编码,然后随时写入输出。这样,您不需要将整个文件读入内存,而只需将其读取到您想要的内容。
如果要最小化(慢速)系统调用的次数,可以使用类似的方法,但显式创建具有更大内部缓冲区的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);
}
}
}