package com.cku.upyun; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; public class UpYun { /** 默认的编码格式 */ private static final String UTF8 = "UTF-8"; /** SKD版本号 */ private final String VERSION = "2.0"; /** 路径的分割符 */ private final String SEPARATOR = "/"; private final String AUTHORIZATION = "Authorization"; private final String DATE = "Date"; private final String CONTENT_LENGTH = "Content-Length"; private final String CONTENT_MD5 = "Content-MD5"; private final String CONTENT_SECRET = "Content-Secret"; private final String MKDIR = "mkdir"; private final String X_UPYUN_WIDTH = "x-upyun-width"; private final String X_UPYUN_HEIGHT = "x-upyun-height"; private final String X_UPYUN_FRAMES = "x-upyun-frames"; private final String X_UPYUN_FILE_TYPE = "x-upyun-file-type"; private final String X_UPYUN_FILE_SIZE = "x-upyun-file-size"; private final String X_UPYUN_FILE_DATE = "x-upyun-file-date"; private final String METHOD_HEAD = "HEAD"; private final String METHOD_GET = "GET"; private final String METHOD_PUT = "PUT"; private final String METHOD_DELETE = "DELETE"; /** * 根据网络条件自动选择接入点:v0.api.upyun.com */ public static final String ED_AUTO = "v0.api.upyun.com"; /** * 电信接入点:v1.api.upyun.com */ public static final String ED_TELECOM = "v1.api.upyun.com"; /** * 联通网通接入点:v2.api.upyun.com */ public static final String ED_CNC = "v2.api.upyun.com"; /** * 移动铁通接入点:v3.api.upyun.com */ public static final String ED_CTT = "v3.api.upyun.com"; // 默认不开启debug模式 public boolean debug = false; // 默认的超时时间:30秒 private int timeout = 30 * 1000; // 默认为自动识别接入点 private String apiDomain = ED_AUTO; // 待上传文件的 Content-MD5 值 private String contentMD5 = null; // 待上传文件的"访问密钥" private String fileSecret = null; // 空间名 protected String bucketName = null; // 操作员名 protected String userName = null; // 操作员密码 protected String password = null; // 图片信息的参数 protected String picWidth = null; protected String picHeight = null; protected String picFrames = null; protected String picType = null; // 文件信息的参数 protected String fileType = null; protected String fileSize = null; protected String fileDate = null; /** * 初始化 UpYun 存储接口 * * @param bucketName * 空间名称 * @param userName * 操作员名称 * @param password * 密码,不需要MD5加密 * @return UpYun object */ public UpYun(String bucketName, String userName, String password) { this.bucketName = bucketName; this.userName = userName; this.password = md5(password); } /** * 切换 API 接口的域名接入点 *
* 可选参数:
* 1) UpYun.ED_AUTO(v0.api.upyun.com):默认,根据网络条件自动选择接入点
* 2) UpYun.ED_TELECOM(v1.api.upyun.com):电信接入点
* 3) UpYun.ED_CNC(v2.api.upyun.com):联通网通接入点
* 4) UpYun.ED_CTT(v3.api.upyun.com):移动铁通接入点
*
* @param domain
* 域名接入点
*/
public void setApiDomain(String domain) {
this.apiDomain = domain;
}
/**
* 查看当前的域名接入点
*
* @return
*/
public String getApiDomain() {
return apiDomain;
}
/**
* 设置连接超时时间,默认为30秒
*
* @param second
* 秒数,60即为一分钟超时
*/
public void setTimeout(int second) {
this.timeout = second * 1000;
}
/**
* 查看当前的超时时间
*
* @return
*/
public int getTimeout() {
return timeout;
}
/**
* 查看当前是否是debug模式
*
* @return
*/
public boolean isDebug() {
return debug;
}
/**
* 设置是否开启debug模式
*
* @param debug
*/
public void setDebug(boolean debug) {
this.debug = debug;
}
/**
* 设置待上传文件的 Content-MD5 值
*
* 如果又拍云服务端收到的文件MD5值与用户设置的不一致,将回报 406 Not Acceptable 错误 * * @param md5Value * 文件 MD5 校验后的内容 */ public void setContentMD5(String md5Value) { this.contentMD5 = md5Value; } /** * 设置待上传文件的"访问密钥" *
* 注意:
* 仅支持图片空!设置密钥后,无法根据原文件URL直接访问,需带 URL 后面加上 (缩略图间隔标志符+密钥) 进行访问
*
* 举例:
* 最终构成的格式:"/空间名/文件路径"
*
* @param path
* 目录路径或文件路径
* @return 格式化后的路径
*/
private String formatPath(String path) {
if (!isEmpty(path)) {
// 去除前后的空格
path = path.trim();
// 确保路径以"/"开头
if (!path.startsWith(SEPARATOR)) {
return SEPARATOR + bucketName + SEPARATOR + path;
}
}
return SEPARATOR + bucketName + path;
}
public class FolderItem {
// 文件名
public String name;
// 文件类型 {file, folder}
public String type;
// 文件大小
public long size;
// 文件日期
public Date date;
public FolderItem(String data) {
String[] a = data.split("\t");
if (a.length == 4) {
this.name = a[0];
this.type = ("N".equals(a[1]) ? "File" : "Folder");
try {
this.size = Long.parseLong(a[2].trim());
} catch (NumberFormatException e) {
this.size = -1;
}
long da = 0;
try {
da = Long.parseLong(a[3].trim());
} catch (NumberFormatException e) {
}
this.date = new Date(da * 1000);
}
}
@Override
public String toString() {
return "time = " + date + " size = " + size + " type = " + type
+ " name = " + name;
}
}
/**
* 其他额外参数的键值和参数值
*/
public enum PARAMS {
/**
* 缩略图类型
*
* 使用场景:上传图片时若无需保存原图,而只需某种特定大小的缩略图,比如说用户头像。
*
* 说明:该参数必须搭配 KEY_X_GMKERL_VALUE 使用,否则无效。另外,使用该参数后将不保存原图,切忌。
*
* 可选参数:
* 说明:该参数必须搭配 KEY_X_GMKERL_TYPE 使用,否则无效。具体的值需要根据 KEY_X_GMKERL_TYPE 而定。
*/
KEY_X_GMKERL_VALUE("x-gmkerl-value"),
/**
* 缩略图质量:图片压缩质量,默认 95
*
* 使用场景:用户上传高保真图片,但自身业务又无需太高质量的图片时,可以设置该参数减少文件保存的大小,从而减少空间的使用量。
*
* 说明:使用该参数后将不保存原图,切忌。
*/
KEY_X_GMKERL_QUALITY("x-gmkerl-quality"),
/**
* 图片锐化:默认锐化(true)
*
* 使用场景:图片处理后质量太差,可以使用该参数模糊边缘,提高图片的清晰度或者焦距程度,使图片特定区域的色彩更加鲜明。
*
* 说明:锐化不是万能的,很容易使图片不真实;另外,也无法通过锐化达到原图的效果。
*/
KEY_X_GMKERL_UNSHARP("x-gmkerl-unsharp"),
/**
* 缩略图版本
*
* 使用场景:快速处理原图,生成自定义的缩略图。
*
* 说明:使用该参数前需要创建好缩略图版本号;另外,使用该参数后将不保存原图,切忌。
*
* @see http://wiki.upyun.com/index.php?title=如何创建自定义缩略图
*/
KEY_X_GMKERL_THUMBNAIL("x-gmkerl-thumbnail"),
/**
* 图片旋转
*
* 使用场景:待上传的图片若是倾斜的,使用该参数可以直接进行强制的或自动的扶正。
*
* 说明:只接受"auto","90","180","270"四种参数,其中"auto"参数根据图片 EXIF
* 中的信息进行自动扶正,若图片没有 EXIF 信息,则该参数无效。另外,使用该参数后将不保存原图,切忌。
*
* @see http://wiki.upyun.com/index.php?title=图片旋转
*/
KEY_X_GMKERL_ROTATE("x-gmkerl-rotate"),
/**
* 图片裁剪
*
* 使用场景:只需要保存待上传图片的某一个部分,比如用户上传头像图片进行裁剪。
*
* 说明:参数格式为x,y,width,height,且需要满足 x >= 0 && y >=0 && width > 0 && height
* > 0
*
* @see http://wiki.upyun.com/index.php?title=图片裁剪
*/
KEY_X_GMKERL_CROP("x-gmkerl-crop"),
/**
* 是否保留exif信息
*
* 使用场景:对于原图包含EXIF信息,在上传图片时又进行了“破坏性处理”(比如裁剪、缩略、自定义版本等),
* upyun默认会删除原图的EXIF信息。 此时搭配该参数可以保留原图的EXIF信息。比如旅游应用从缩略图中获取具体的地理信息。
*
* 说明:仅搭配"破坏性处理"的参数使用时有效,其他处理均无效;另外key对应的值仅设置为"true"时有效;
*/
KEY_X_GMKERL_EXIF_SWITCH("x-gmkerl-exif-switch"),
/**
* 创建目录
*
* 说明:SDK内部使用
*/
KEY_MAKE_DIR("folder"),
/**
* 缩略图类型之 "限定最长边,短边自适应",参数为像素值,如: 150
*/
VALUE_FIX_MAX("fix_max"),
/**
* 缩略图类型之 "限定最短边,长边自适应",参数为像素值,如: 150
*/
VALUE_FIX_MIN("fix_min"),
/**
* 缩略图类型之 "限定宽度和高度",参数为像素值,如: 150x130
*/
VALUE_FIX_WIDTH_OR_HEIGHT("fix_width_or_height"),
/**
* 缩略图类型之 "限定宽度,高度自适应",参数为像素值,如: 150
*/
VALUE_FIX_WIDTH("fix_width"),
/**
* 缩略图类型之 "限定高度,宽度自适应",参数为像素值,如: 150
*/
VALUE_FIX_HEIGHT("fix_height"),
/**
* 缩略图类型之 "方块图,固定高固定宽",参数为像素值,如: 150
*/
VALUE_SQUARE("square"),
/**
* 缩略图类型之 "固定宽度和高度",参数为像素值,如: 150x130
*/
VALUE_FIX_BOTH("fix_both"),
/**
* 缩略图类型之 "等比例缩放",参数为比例值(1-99),如: 50
*/
VALUE_FIX_SCALE("fix_scale"),
/**
* 图片旋转之 "自动扶正"
*/
VALUE_ROTATE_AUTO("auto"),
/**
* 图片旋转之 "旋转90度"
*/
VALUE_ROTATE_90("90"),
/**
* 图片旋转之 "旋转180度"
*/
VALUE_ROTATE_180("180"),
/**
* 图片旋转之 "旋转270度"
*/
VALUE_ROTATE_270("270");
private final String value;
private PARAMS(String val) {
value = val;
}
public String getValue() {
return value;
}
}
}
* 如果缩略图间隔标志符为"!",密钥为"bac",上传文件路径为"/folder/test.jpg",
* 那么该图片的对外访问地址为:http://空间域名 /folder/test.jpg!bac
*
* @param secret
* 密钥字符串
*/
public void setFileSecret(String secret) {
this.fileSecret = secret;
}
public String getPicWidth() {
return picWidth;
}
public String getPicHeight() {
return picHeight;
}
public String getPicFrames() {
return picFrames;
}
public String getPicType() {
return picType;
}
/**
* 获取当前SDK的版本号
*
* @return SDK版本号
*/
public String version() {
return VERSION;
}
/**
* 获取总体空间的占用量
*
* @param path
* 目标路径
* @return 空间占用量,失败时返回 -1
*/
public long getBucketUsage() {
long usage = -1;
String result = HttpAction(METHOD_GET, formatPath("/") + "/?usage");
if (!isEmpty(result)) {
try {
usage = Long.parseLong(result.trim());
} catch (NumberFormatException e) {
}
}
return usage;
}
/**
* 获取某个子目录的占用量
*
* @param path
* 目标路径
* @return 空间占用量,失败时返回 -1
*/
@Deprecated
public long getFolderUsage(String path) {
long usage = -1;
String result = HttpAction(METHOD_GET, formatPath(path) + "/?usage");
if (!isEmpty(result)) {
try {
usage = Long.parseLong(result.trim());
} catch (NumberFormatException e) {
}
}
return usage;
}
/**
* 上传文件
*
* @param filePath
* 文件路径(包含文件名)
* @param datas
* 文件内容
*
* @return true or false
*/
public boolean writeFile(String filePath, byte[] datas) {
return writeFile(filePath, datas, false, null);
}
/**
* 上传文件
*
* @param filePath
* 文件路径(包含文件名)
* @param datas
* 文件内容
* @param auto
* 是否自动创建父级目录(最多10级)
*
* @return true or false
*/
public boolean writeFile(String filePath, byte[] datas, boolean auto) {
return writeFile(filePath, datas, auto, null);
}
/**
* 上传文件
*
* @param filePath
* 文件路径(包含文件名)
* @param datas
* 文件内容
* @param auto
* 是否自动创建父级目录(最多10级)
* @param params
* 额外参数
*
* @return true or false
*/
public boolean writeFile(String filePath, byte[] datas, boolean auto,
Map
* 1)VALUE_FIX_MAX("fix_max"):"限定最长边,短边自适应"
* 2)VALUE_FIX_MIN("fix_min"):"限定最短边,长边自适应"
* 3)VALUE_FIX_WIDTH_OR_HEIGHT("fix_width_or_height"):"限定宽度和高度"
* 4)VALUE_FIX_WIDTH("fix_width"):"限定宽度,高度自适应"
* 5)VALUE_FIX_HEIGHT("fix_height"):"限定高度,宽度自适应"
* 6)VALUE_FIX_BOTH("fix_both"):"固定宽度和高度"
* 7)VALUE_FIX_SCALE("fix_scale"):"等比例缩放"
* 8)VALUE_SQUARE("square"):"方块图,固定高固定宽"
*
* @see 参数举例:http://wiki.upyun.com/index.php?title=缩略图方式差别举例
*/
KEY_X_GMKERL_TYPE("x-gmkerl-type"),
/**
* 缩略图参数值
*