我们在开发过程中经常需要在控制台打印日志来进行调试,但是会发现日志内容过长的情况下,就无法完整的输出全部内容,这是因为 Log 日志最大长度为 4096 字节,超过这个长度的部分就无法显示。下面给出几个解决方案:
方式一:
private static final int MAX_LOG_BYTES = 4096;public static void largeLog(String tag, String content) {if (content.length() > MAX_LOG_BYTES) {Log.d(tag, content.substring(0, MAX_LOG_BYTES));largeLog(tag, content.substring(MAX_LOG_BYTES));} else {Log.d(tag, content);}
}
以上代码初看起来,简洁优雅,但实际上存在问题,Log 日志的最大长度 4096 是指的字节长度,如果输出的日志内容都是 ASCII 编码的字符(单字节的字符),这样写是可以的。但是如果日志内容包括 UTF8 编码的中文字符(1-4个字节),所以上面代码中的:content.substring(0, MAX_LOG_BYTES),“4096 长度的字符串”包括的字节数会超出 4096 字节(日志最大字节数),仍然会导致分段输出的日志可能不完整。
根据上面的分析,如果输出的日志(字符串)不仅仅包括单字节字符(包括中文字符),可以考虑将上面的 MAX_LOG_BYTES 的值修改的低一些,例如1000,2000等。这样处理虽然比较简单,但略显粗糙,因此我们可以考虑用更精准的 “方式二” 与 “方式三” 来实现。
方式二:
# 由于日志的tag, priority(assert, debug, ...), etc. 会占用一些字节,这里4096是一个理想值。# 建议这里设置一个小于4096 的值,例如一个比较保守的值 4000 # private static final int MAX_LOG_BYTES = 4096;private static final int MAX_LOG_BYTES = 4000;public static void largeLog(int priority, String tag, @NonNull String content) {int size = content.getBytes(StandardCharsets.UTF_8).length;if (size > MAX_LOG_BYTES) {String text = trim(content, MAX_LOG_BYTES);Log.println(priority, tag, text);largeLog(priority, tag, content.substring(text.length()));} else {Log.println(priority, tag, content);}}public static String trim(String text, int size) {byte[] inputBytes = text.getBytes(StandardCharsets.UTF_8);byte[] outputBytes = new byte[size];System.arraycopy(inputBytes, 0, outputBytes, 0, size);String result = new String(outputBytes, StandardCharsets.UTF_8);// check if last character is truncatedint lastIndex = result.length() - 1;if (lastIndex > 0 && result.charAt(lastIndex) != text.charAt(lastIndex)) {// last character is truncated so remove the last characterreturn result.substring(0, lastIndex);}return result;}
方式三:
# 由于日志的tag, priority(assert, debug, ...), etc. 会占用一些字节,这里4096是一个理想值。# 建议这里设置一个小于4096 的值,例如一个比较保守的值 4000 # private static final int MAX_LOG_BYTES = 4096;private static final int MAX_LOG_BYTES = 4000; public static void largeLog(String tag, String str) {String[] logs = SplitStringByByteLength(str, "UTF-8", MAX_LOG_BYTES );for(String log : logs) {Log.i(tag, log);}}public static String[] SplitStringByByteLength(String src, String encoding, int maxsize) {Charset cs = Charset.forName(encoding);CharsetEncoder coder = cs.newEncoder();ByteBuffer out = ByteBuffer.allocate(maxsize); // output buffer of required sizeCharBuffer in = CharBuffer.wrap(src);List<String> ss = new ArrayList<>(); // a list to store the chunksint pos = 0;while(true) {CoderResult cr = coder.encode(in, out, true); // try to encode as much as possibleint newpos = src.length() - in.length();String s = src.substring(pos, newpos);ss.add(s); // add what has been encoded to the listpos = newpos; // store new input positionout.rewind(); // and rewind output bufferif (! cr.isOverflow()) {break; // everything has been encoded}}return ss.toArray(new String[0]);}
参考:
Android - Set max length of logcat messages