com.jianggujin.http.util.JDataUtils Maven / Gradle / Ivy
/**
* Copyright 2018 jianggujin (www.jianggujin.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jianggujin.http.util;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.IllegalCharsetNameException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 数据工具
*
* @author jianggujin
*
*/
public final class JDataUtils {
/**
* 字符集正则匹配模式
*/
private static final Pattern CHARSET_PATTERN = Pattern.compile("(?i)\\bcharset=\\s*(?:\"|')?([^\\s,;\"']*)");
/**
* 默认字符集
*/
public static final String DEFAULT_CHARSET = "UTF-8";
/**
* 默认超时时间
*/
public static final int DEFAULT_TIME_OUT = 5000;
/**
* 缓冲区大小
*/
private static final int BUFFER_SIZE = 0x20000; // ~130K.
/**
* mime边界字符数组
*/
private static final char[] MIME_BOUNDARY_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
.toCharArray();
/**
* mime边界长度
*/
private static final int BOUNDARY_LENGTH = 32;
/**
* 空字符串数组
*/
public static final String[] EMPTY_STRING_ARRAY = new String[0];
private JDataUtils() {
}
/**
* 将输入流数据写入到输出流,不关闭相关流
*
* @param in 输入流
* @param out 输出流
* @throws IOException
*/
public static void crossStreams(final InputStream in, final OutputStream out) throws IOException {
final byte[] buffer = new byte[BUFFER_SIZE];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
out.flush();
}
/**
* 从输入流读取数据到字节缓冲区
*
* @param in 输入流
* @param maxSize 从输入流中读取的最大长度,设置为0不限制
* @return
* @throws IOException
*/
public static ByteBuffer readToByteBuffer(InputStream in, int maxSize) throws IOException {
if (maxSize < 0) {
throw new IllegalArgumentException("maxSize must be 0 (unlimited) or larger");
}
final boolean capped = maxSize > 0;
byte[] buffer = new byte[BUFFER_SIZE];
ByteArrayOutputStream outStream = new ByteArrayOutputStream(BUFFER_SIZE);
int read;
int remaining = maxSize;
while (true) {
read = in.read(buffer);
if (read == -1) {
break;
}
if (capped) {
if (read > remaining) {
outStream.write(buffer, 0, remaining);
break;
}
remaining -= read;
}
outStream.write(buffer, 0, read);
}
return ByteBuffer.wrap(outStream.toByteArray());
}
/**
* 从输入流读取数据到字节缓冲区
*
* @param in 输入流
* @return
* @throws IOException
*/
public static ByteBuffer readToByteBuffer(InputStream in) throws IOException {
return readToByteBuffer(in, 0);
}
/**
* 从文件中读取数据到字节缓冲区
*
* @param file 文件
* @return
* @throws IOException
*/
public static ByteBuffer readFileToByteBuffer(File file) throws IOException {
RandomAccessFile randomAccessFile = null;
try {
randomAccessFile = new RandomAccessFile(file, "r");
byte[] bytes = new byte[(int) randomAccessFile.length()];
randomAccessFile.readFully(bytes);
return ByteBuffer.wrap(bytes);
} finally {
if (randomAccessFile != null) {
randomAccessFile.close();
}
}
}
/**
* 将输入流解析成字符串
*
* @param in
* @param charset
* @return
* @throws IOException
*/
public static String readToString(InputStream in, String charset) throws IOException {
ByteBuffer buffer = JDataUtils.readToByteBuffer(in);
String body;
if (charset == null) {
body = Charset.forName(JDataUtils.DEFAULT_CHARSET).decode(buffer).toString();
} else {
body = Charset.forName(charset).decode(buffer).toString();
}
return body;
}
/**
* 空的字节缓冲区
*
* @return
*/
public static ByteBuffer emptyByteBuffer() {
return ByteBuffer.allocate(0);
}
/**
* 从Content-Type头中解析字符集,如果该字符集不被支持则返回null
*
* @param contentType 示例 "text/html; charset=EUC-JP"
* @return "EUC-JP", or null if not found. Charset is trimmed and uppercased.
*/
public static String getCharsetFromContentType(String contentType) {
if (contentType == null) {
return null;
}
Matcher m = CHARSET_PATTERN.matcher(contentType);
if (m.find()) {
String charset = m.group(1).trim();
charset = charset.replace("charset=", "");
return validateCharset(charset);
}
return null;
}
/**
* 验证字符集
*
* @param cs
* @return
*/
public static String validateCharset(String cs) {
if (cs == null || cs.length() == 0) {
return null;
}
cs = cs.trim().replaceAll("[\"']", "");
try {
if (Charset.isSupported(cs)) {
return cs;
}
cs = cs.toUpperCase(Locale.ENGLISH);
if (Charset.isSupported(cs)) {
return cs;
}
} catch (IllegalCharsetNameException e) {
}
return null;
}
/**
* 创建一个用于mime边界的随随机字符串
*/
public static String mimeBoundary() {
final StringBuilder mime = new StringBuilder(BOUNDARY_LENGTH);
final Random rand = new Random();
for (int i = 0; i < BOUNDARY_LENGTH; i++) {
mime.append(MIME_BOUNDARY_CHARS[rand.nextInt(MIME_BOUNDARY_CHARS.length)]);
}
return mime.toString();
}
/**
* 将url中的空格转化成%20
*
* @param url
* @return
*/
public static String encodeUrl(String url) {
if (url == null) {
return null;
}
return url.replaceAll(" ", "%20");
}
/**
* 编码mime
*
* @param val
* @return
*/
public static String encodeMimeName(String val) {
if (val == null) {
return null;
}
return val.replaceAll("\"", "%22");
}
/**
* 判断字符串是否为空
*
* @param str
* @return
*/
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
/**
* 用提供的数据替换掉字符串中内容
*
* @param text
* @param bindRes
* @return
*/
public static String resolveDynamicPropnames(String text, Map bindRes) {
return resolveDynamicPropnames(text, bindRes, "${", "}");
}
/**
* 用提供的数据替换掉字符串中内容
*
* @param text
* @param bindRes
* @param prefix 插值前缀
* @param suffix 插值后缀
* @return
*/
public static String resolveDynamicPropnames(String text, Map bindRes, String prefix,
String suffix) {
if (text == null) {
return text;
}
int startIndex = text.indexOf(prefix);
if (startIndex == -1) {
return text;
}
String tempStr = text;
StringBuilder result = new StringBuilder(text.length() + 32);
int prefixLength = prefix.length();
while (startIndex != -1) {
result.append(tempStr.substring(0, startIndex));
int endIndex = tempStr.indexOf(suffix, startIndex + prefixLength);
if (endIndex != -1) {
String dName = tempStr.substring(startIndex + prefixLength, endIndex);
try {
String pValue = null;
if (bindRes != null) {
Object obj = bindRes.get(dName);
if (obj != null) {
pValue = String.valueOf(obj);
}
}
if (pValue != null) {
result.append(resolveDynamicPropnames(pValue, bindRes));
} else {
result.append(tempStr.substring(startIndex, endIndex + 1));
}
} catch (Throwable ex) {
}
tempStr = tempStr.substring(endIndex + suffix.length());
startIndex = tempStr.indexOf(prefix);
} else {
tempStr = tempStr.substring(startIndex);
startIndex = -1;
}
}
result.append(tempStr);
return result.toString();
}
/**
* 根据指定的分隔符delimiter
分割一个字符串 str
.
*
* 如果给出的字符串str
为null
、空串 ""
,则返回
* null
,只包含分隔符 delimiter
,则返回长度为0的字符串数组。如果给出的 字符串
* str
可以分割,即不在上述情况之列,则返回一个 字符串数组,每个单元包含一个被分隔出来的字符串。
*
* 例如:
*
*
* StringProcessor.separateString("一,二,三", ",")
* 返回 {"一", "二", "三"}
* StringProcessor.separateString("你好,大家好!我很好。", ",!")
* 返回 {"你好", "大家好", "我很好。"}
* StringProcessor.separateString(null, ", \t\r\n")
* 返回 null
* StringProcessor.separateString(", , , , ", ", \n")
* 返回 {}
*
*
*
*
* @param str 要进行分割的字符串
* @param delimiter 分隔符集合
* @return 分割后的字符串所组成的数组
*/
public static String[] separateString(String str, String delimiter) {
return separateString(str, delimiter, false);
}
/**
* 根据指定的分隔符delimiter
分割一个字符串 str
.
*
*
* @param str 要进行分割的字符串
* @param delimiter 分隔符集合
* @param trim 是否要对分割出来的每个字符串进行去除空格处理
* @return 分割后的字符串所组成的数组
*/
public static String[] separateString(String str, String delimiter, boolean trim) {
if (str == null) {
return null;
}
int count = str.length();
if (count == 0) {
return EMPTY_STRING_ARRAY;
}
if (isEmpty(delimiter)) {
delimiter = " \t\n\r\f";
}
List list = new ArrayList();
int i = 0;
int begin = 0;
boolean notMatch = false;
if (delimiter.length() == 1) {
// 仅有一个字符时用字符比较来判断
char c = delimiter.charAt(0);
while (i < count) {
if (str.charAt(i) == c) {
if (notMatch) {
list.add(trim ? str.substring(begin, i).trim() : str.substring(begin, i));
notMatch = false;
}
begin = ++i;
continue;
}
notMatch = true;
i++;
}
} else {
// 有多个字符时用字符串的包含字符来判断
while (i < count) {
if (delimiter.indexOf(str.charAt(i)) >= 0) {
if (notMatch) {
list.add(trim ? str.substring(begin, i).trim() : str.substring(begin, i));
notMatch = false;
}
begin = ++i;
continue;
}
notMatch = true;
i++;
}
}
if (notMatch) {
list.add(trim ? str.substring(begin, i).trim() : str.substring(begin, i));
}
return (String[]) list.toArray(new String[list.size()]);
}
/**
* 将字符串数组arr
用链接符link
链接成一个字符串.
*
*
* @param arr 要链接的字符串数组
* @param link 链接符
* @return 用链接符链接后的字符串
*/
public static String linkStringArr(String[] arr, String link) {
if (arr == null || arr.length == 0) {
return "";
}
if (arr.length == 1) {
return arr[0];
}
link = link == null ? "" : link;
StringBuilder buf = new StringBuilder(arr.length * (link.length() + 16));
buf.append(arr[0]);
for (int i = 1; i < arr.length; i++) {
buf.append(link).append(arr[i]);
}
return buf.toString();
}
/**
* 将字符串按照一定的格式转换成Map.
*
*
* @param str 要转换成Map的字符串
* @param itemDelimiter Map元素的分隔符集合
* @param kvDelimiter key和value的分隔符
* @return 转换后的Map对象
*/
public static Map string2Map(String str, String itemDelimiter, char kvDelimiter) {
return string2Map(str, itemDelimiter, kvDelimiter, true, true, null, null);
}
/**
* 将字符串按照一定的格式转换成Map.
*
*
* @param str 要转换成Map的字符串
* @param itemDelimiter Map元素的分隔符集合
* @param kvDelimiter key和value的分隔符
* @param trimItem 是否要对每个元素进行trim
* @param needResolve 是否要处理文本中"${...}"的动态属性
* @param resolveRes 处理动态属性时绑定的资源
* @param result 将转换的结果放入此Map中
* @return 转换后的Map对象
*/
public static Map string2Map(String str, String itemDelimiter, char kvDelimiter, boolean trimItem,
boolean needResolve, Map resolveRes, Map result) {
if (str == null) {
return null;
}
if (result == null) {
result = new HashMap();
}
if (needResolve) {
str = resolveDynamicPropnames(str, resolveRes);
}
String[] arr = separateString(str, itemDelimiter, trimItem);
for (int i = 0; i < arr.length; i++) {
int index = arr[i].indexOf(kvDelimiter);
if (index != -1) {
String k = arr[i].substring(0, index);
String v = arr[i].substring(index + 1);
result.put(trimItem ? k.trim() : k, trimItem ? v.trim() : v);
} else if (arr[i].length() > 0) {
if (trimItem) {
String trimStr = arr[i].trim();
if (trimStr.length() > 0) {
result.put(trimStr, "");
}
} else {
result.put(arr[i], "");
}
}
}
return result;
}
public static void close(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException e) {
}
}
}
public static String toString(Object obj) {
if (obj == null || obj instanceof String)
return (String) obj;
return obj.toString();
}
public static boolean equals(String src1, String src2) {
return src1 == null ? src2 == null : src1.equals(src2);
}
}