文件上传工具类

作者: Fitz_e74a | 来源:发表于2019-05-24 15:51 被阅读33次

背景

最近由于项目需求,需要抓取上传app的日志,方便问题追踪,同时给其他公司其他项目进行依赖使用,因此需要打成aar库。

实现

使用Retrfit 进行网络部分的请求,Retrfit的依赖

   implementation 'com.squareup.retrofit2:retrofit:2.3.0'
    implementation "com.squareup.okhttp3:logging-interceptor:3.8.1"

采用后台服务的方式,进行日志上传,同时上传完成之后,自动销毁任务,因为采用IntentService

代码部分

public class UploadFileService extends IntentService {

    private static final String TAG = "UploadFileService";
    private SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("yyyyMMdd");

    private UploadServiceApi mUploadServiceApi;


    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public UploadFileService(String name) {
        super(name);
    }

    public UploadFileService() {
        this("NEW_UPLOAD");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mUploadServiceApi = RetrfitApiUtil.getService(UploadServiceApi.class, "");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        List<File> files = getNeedUploadFiles();
        File zipFile = ZipUtils.zipFiles(files, mSimpleDateFormat.format(new Date()) + ".zip");
        Log.d(TAG, "zipFile " + zipFile.length() + zipFile.getAbsolutePath());
        RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), zipFile);
        MultipartBody.Part body = MultipartBody.Part.createFormData("file", zipFile.getName(), requestFile);
        Map<String, RequestBody> map = getUploadParamsMap();

        Call<ResponseBody> call = mUploadServiceApi.uploadLogFile(UploadUtil.getUrl(), map, body);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
                Log.d(TAG, "上传成功" + response.toString());
                ZipUtils.deleteZipFile();
            }

            @Override
            public void onFailure(Call<ResponseBody> call, Throwable t) {
                Log.e(TAG, t.toString());
            }
        });

    }

    private Map<String, RequestBody> getUploadParamsMap() {
        Map<String, RequestBody> newMap = new HashMap<>();
        Map<String, Object> map = UploadUtil.getmParamMap();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
            newMap.put(entry.getKey(), toRequestBody(entry.getValue()));
        }

        return newMap;
    }

    private List<File> getNeedUploadFiles() {

        List<File> files = new ArrayList<>();
        File fileDir = new File(UploadUtil.getLocation());
        if (fileDir.isDirectory()) {
            File[] fileArray = fileDir.listFiles();
            files = new ArrayList<>(Arrays.asList(fileArray));
        }
        List<File> newFiles = new ArrayList<>();
        for (File file : files) {
            if (UploadUtil.getDatas() == null || UploadUtil.getDatas().isEmpty()) break;
            for (String fileName : UploadUtil.getDatas()) {
                if (file.getName().contains(fileName)) {
                    newFiles.add(file);
                    break;
                }
            }
        }
        return newFiles;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();

    }

    private RequestBody toRequestBody(Object value) {
        String newValue;
        if (value instanceof String) {
            newValue = (String) value;
        } else if (value != null) {
            newValue = value.toString();
        } else {
            newValue = "";
        }
        RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), newValue);
        return requestBody;
    }

}

Retrfit接口定义

public interface UploadServiceApi {

    /**
     * 上传日志文件/到服务器
     * @return
     */
    @Multipart
    @POST
    Call<ResponseBody> uploadLogFile(@Url String url, @PartMap Map<String, RequestBody> files, @Part MultipartBody.Part file);
}

服务器地址由接口直接传入,因此host直接传null即可

public class RetrfitApiUtil {

    /**
     * @param tClass retrofitAPI 类
     * @param host   服务器地址(必须以 / 结尾)
     * @return
     */
    public static <T> T getService(Class<T> tClass, String host) {
        //网络日志
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY );
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .addInterceptor(interceptor);
        OkHttpClient okHttpClient = builder.connectTimeout(15000L, TimeUnit.MILLISECONDS)
                .readTimeout(15000L, TimeUnit.MILLISECONDS)
                .build();

        if (TextUtils.isEmpty(host)) {
            host = "http://localhost/";
        }


        Retrofit retrofit = new Retrofit.Builder().baseUrl(host)
                .client(okHttpClient)
                .build();

        return retrofit.create(tClass);
    }

}

可能需要进行多个文件进行上传,因此需要打包,ZipUtil工具栏

public class ZipUtils {


    public static File zipFiles(List<File> srcFiles, String zipFileName) {
        // 判断压缩后的文件存在不,不存在则创建
        File zipFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/T3出行/Log", zipFileName);
        createOrExistsFile(zipFile);
        // 创建 FileOutputStream 对象
        FileOutputStream fileOutputStream = null;
        // 创建 ZipOutputStream
        ZipOutputStream zipOutputStream = null;
        // 创建 FileInputStream 对象
        FileInputStream fileInputStream = null;

        try {
            // 实例化 FileOutputStream 对象
            fileOutputStream = new FileOutputStream(zipFile);
            // 实例化 ZipOutputStream 对象
            zipOutputStream = new ZipOutputStream(fileOutputStream);
            // 创建 ZipEntry 对象
            ZipEntry zipEntry = null;
            // 遍历源文件数组
            for (int i = 0; i < srcFiles.size(); i++) {
                // 将源文件数组中的当前文件读入 FileInputStream 流中
                fileInputStream = new FileInputStream(srcFiles.get(i));
                // 实例化 ZipEntry 对象,源文件数组中的当前文件
                zipEntry = new ZipEntry(srcFiles.get(i).getName());
                zipOutputStream.putNextEntry(zipEntry);
                // 该变量记录每次真正读的字节个数
                int len;
                // 定义每次读取的字节数组
                byte[] buffer = new byte[1024];
                while ((len = fileInputStream.read(buffer)) > 0) {
                    zipOutputStream.write(buffer, 0, len);
                }
            }
            if (zipEntry != null) {
                zipOutputStream.closeEntry();
            }
            zipOutputStream.close();
            fileInputStream.close();
            fileOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return zipFile;
    }


    public static void deleteZipFile() {
        File zipFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/T3出行/Log");
        deleteFile(zipFile);

    }
    /***
     * 删除压缩后的文件
     */
    /**
     * 先根遍历序递归删除文件夹
     *
     * @param dirFile 要被删除的文件或者目录
     * @return 删除成功返回true, 否则返回false
     */
    public static boolean deleteFile(File dirFile) {
        // 如果dir对应的文件不存在,则退出
        if (!dirFile.exists()) {
            return false;
        }

        if (dirFile.isFile()) {
            return dirFile.delete();
        } else {

            for (File file : dirFile.listFiles()) {
                deleteFile(file);
            }
        }

        return dirFile.delete();
    }


    /**
     * 判断文件是否存在,不存在则判断是否创建成功
     *
     * @param file 文件
     * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
     */
    public static boolean createOrExistsFile(final File file) {
        if (file == null) return false;
        // 如果存在,是文件则返回 true,是目录则返回 false
        if (file.exists()) return file.isFile();
        if (!createOrExistsDir(file.getParentFile())) return false;
        try {
            return file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 判断目录是否存在,不存在则判断是否创建成功
     *
     * @param file 文件
     * @return {@code true}: 存在或创建成功<br>{@code false}: 不存在或创建失败
     */
    public static boolean createOrExistsDir(final File file) {
        // 如果存在,是目录则返回 true,是文件则返回 false,不存在则返回是否创建成功
        return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
    }
}

App或者其他库调用的入口UploadUtil,
url 为上传的服务器地址,location为需要上传文件的目录,datas为需要上传文件的文件名的集合,logKey为公司项目统一要求字段,其他库可以直接传null

public class UploadUtil {

    private static boolean test = false;


    /**
     * 请求参数map
     */
    private static HashMap<String, Object> mParamMap;
    private static String url;
    private static String location;
    private static List<String> datas;
    private static Context context;


    public static void setLogKey(String logKey) {
        if (mParamMap == null) {
            mParamMap = new HashMap<>();
        }
        mParamMap.put("logKey", logKey);
    }

    public static String getUrl() {
        return url;
    }

    public static void setUrl(String url) {
        UploadUtil.url = url;
    }

    public static String getLocation() {
        return location;
    }

    public static void setLocation(String location) {
        UploadUtil.location = location;
    }

    public static List<String> getDatas() {
        return datas;
    }

    public static void setDatas(List<String> datas) {
        UploadUtil.datas = datas;
    }

    public static HashMap<String, Object> getmParamMap() {
        return mParamMap;
    }

    public static void setmParamMap(HashMap<String, Object> mParamMap) {
        UploadUtil.mParamMap = mParamMap;
    }


    public static void init(Context context, HashMap<String, Object> map) {
        UploadUtil.context = context;
        mParamMap = map;
    }


    public static void prepare(String url, String location) {
        UploadUtil.url = url;
        UploadUtil.location = location;

    }

    public static void uploadFile(String logKey, List<String> datas) throws Exception {
        setLogKey(logKey);
        UploadUtil.datas = datas;
        if (test) {
            UploadUtil.datas = new ArrayList<>(Arrays.asList("Screenshot_20190506-180709.jpg", "Screenshot_20190505-102016_3D.jpg"));
        }
        if (context != null && mParamMap != null) {
            context.startService(new Intent(context, UploadFileService.class));
        } else {
            throw new Exception("please init context & paramMap first");
        }
    }

    public static void uploadFile(String logKey, String fileName) throws Exception {
        Log.d("UploadUtil",fileName+"===="+logKey);
        setLogKey(logKey);
        UploadUtil.datas =  new ArrayList<>(Arrays.asList(fileName));
        if (test) {
            UploadUtil.datas = new ArrayList<>(Arrays.asList("Screenshot_20190506-180709.jpg", "Screenshot_20190505-102016_3D.jpg"));
        }
        if (context != null && mParamMap != null) {
            context.startService(new Intent(context, UploadFileService.class));
        } else {
            throw new Exception("please init context & paramMap first");
        }
    }

}

使用方法

  1. 先调用UploadUtil.init()进行文件夹目录和基本上传参数的构建,比如token等
  2. 其次,调用UploadUtil.prepare()设置需要上传的服务器地址和文件目录
  3. 最后,UploadUtil.uploadFile()进行文件开始的上传,由于采用IntentService,多次调用,也会在队列里一个个进行上传,任务全部结束之后,service自动销毁

相关文章

网友评论

    本文标题:文件上传工具类

    本文链接:https://www.haomeiwen.com/subject/skagzqtx.html