一、中文亂碼問題
默認情況下,在windows上用excel打開csv文件時,並不是按utf-8碼解析的,就算代碼里設置了寫入字符串為utf-8字符集,也可能亂碼。
需要在文件頭寫入幾個特殊的字節,做為utf-8的BOM頭。
/** * utf-8的bom頭 */ byte[] UTF8_HEADER_BOM = new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
建議導出后,用一些編輯工具查看16進制格式,確認前3個字節是否ef bb bf
二、大數字被顯示為科學計數法的問題
一些產品編碼,比如100000000001,打開后,會變成:
可在文本后加\t解決
三、海量數據寫入時如何避免OOM
通常我們會把內容先拼成一個String,然后一次性寫入,如果數據量巨大,比如上千萬,一次性拼接很容易造成OOM。可以借用內存映射(NIO中的技術)優化。
RandomAccessFile file = new RandomAccessFile(csvFileName, "rw"); FileChannel channel = file.getChannel(); MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, file.length(), UTF8_HEADER_BOM.length); mappedByteBuffer.put(UTF8_HEADER_BOM);
完整示例:
/** * csv寫入示例(菩提樹下的楊過 http://yjmyzz.cnblogs.com) * * @throws IOException */ private static void testCsv() throws IOException { /** * utf-8的bom頭 */ byte[] UTF8_HEADER_BOM = new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}; String csvFileName = "D:\\temp\\test.csv"; FileUtils.deleteQuietly(new File(csvFileName)); RandomAccessFile file = new RandomAccessFile(csvFileName, "rw"); FileChannel channel = file.getChannel(); byte[] header = "編號,品名,時間戳\n".getBytes("UTF-8"); //寫入utf8的bom頭,防止打開csv時顯示亂碼 MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, file.length(), UTF8_HEADER_BOM.length); mappedByteBuffer.put(UTF8_HEADER_BOM); //寫入標題欄 mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, file.length(), header.length); mappedByteBuffer.put(header); //分批寫入記錄(每批1000條)-防止OOM long timestamp = System.currentTimeMillis(); for (int i = 1; i <= 100; i++) { StringBuilder sb = new StringBuilder(); for (int j = 1; j <= 1000; j++) { sb.append(i * j + "\t,"); sb.append("產品" + j + ","); sb.append(timestamp + "\t\n"); } byte[] data = sb.toString().getBytes("UTF-8"); mappedByteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, file.length(), data.length); mappedByteBuffer.put(data); } //關閉通道 channel.close(); }
導出效果: