Java实现本地APK文件搜索与HTTP下载服务

下面我将提供一个完整的Java实现方案,用于在本地文件系统中搜索APK文件,并通过HTTP服务提供下载功能。

图片[1]_Java实现本地APK文件搜索与HTTP下载服务_知途无界

1. 项目结构

APKDownloadService/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/apkservice/
│   │   │       ├── ApkFile.java          // APK文件模型
│   │   │       ├── ApkSearcher.java      // APK文件搜索器
│   │   │       ├── DownloadServer.java   // HTTP下载服务器
│   │   │       └── Main.java             // 主程序入口
│   │   └── resources/
│   └── test/
│       └── java/                         // 测试代码
└── pom.xml                              // Maven配置文件

2. 实现代码

2.1 APK文件模型 (ApkFile.java)

package com.example.apkservice;

import java.io.File;

public class ApkFile {
    private String name;
    private String packageName;
    private String version;
    private long size;
    private File file;
    private String path;

    public ApkFile(File file) {
        this.file = file;
        this.name = file.getName();
        this.path = file.getAbsolutePath();
        this.size = file.length();
        // 实际应用中可以从APK中解析包名和版本号
        this.packageName = "unknown";
        this.version = "unknown";
    }

    // Getters and Setters
    public String getName() { return name; }
    public String getPackageName() { return packageName; }
    public String getVersion() { return version; }
    public long getSize() { return size; }
    public File getFile() { return file; }
    public String getPath() { return path; }
}

2.2 APK文件搜索器 (ApkSearcher.java)

package com.example.apkservice;

import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.List;

public class ApkSearcher {
    private static final String APK_EXTENSION = ".apk";

    public List<ApkFile> searchApkFiles(String rootPath) {
        List<ApkFile> apkFiles = new ArrayList<>();
        File root = new File(rootPath);

        if (!root.exists() || !root.isDirectory()) {
            throw new IllegalArgumentException("Invalid root path: " + rootPath);
        }

        searchApkFilesRecursive(root, apkFiles);
        return apkFiles;
    }

    private void searchApkFilesRecursive(File directory, List<ApkFile> apkFiles) {
        File[] files = directory.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                return file.isDirectory() || 
                      (file.isFile() && file.getName().toLowerCase().endsWith(APK_EXTENSION));
            }
        });

        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                searchApkFilesRecursive(file, apkFiles);
            } else {
                apkFiles.add(new ApkFile(file));
            }
        }
    }
}

2.3 HTTP下载服务器 (DownloadServer.java)

package com.example.apkservice;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;

public class DownloadServer {
    private HttpServer server;
    private List<ApkFile> apkFiles;
    private int port;

    public DownloadServer(List<ApkFile> apkFiles, int port) {
        this.apkFiles = apkFiles;
        this.port = port;
    }

    public void start() throws IOException {
        server = HttpServer.create(new InetSocketAddress(port), 0);
        server.createContext("/", new RootHandler());
        server.createContext("/download", new DownloadHandler());
        server.createContext("/list", new ListHandler());
        server.setExecutor(Executors.newCachedThreadPool());
        server.start();
        System.out.println("Server started on port " + port);
    }

    public void stop() {
        if (server != null) {
            server.stop(0);
            System.out.println("Server stopped");
        }
    }

    private class RootHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            String response = "<html><body>" +
                    "<h1>APK Download Service</h1>" +
                    "<p><a href='/list'>View APK List</a></p>" +
                    "</body></html>";
            exchange.sendResponseHeaders(200, response.length());
            OutputStream os = exchange.getResponseBody();
            os.write(response.getBytes());
            os.close();
        }
    }

    private class ListHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            StringBuilder sb = new StringBuilder();
            sb.append("<html><body>");
            sb.append("<h1>Available APK Files</h1>");
            sb.append("<table border='1'>");
            sb.append("<tr><th>Name</th><th>Size</th><th>Action</th></tr>");

            for (ApkFile apk : apkFiles) {
                sb.append("<tr>");
                sb.append("<td>").append(apk.getName()).append("</td>");
                sb.append("<td>").append(formatFileSize(apk.getSize())).append("</td>");
                sb.append("<td><a href='/download?file=")
                  .append(apk.getPath().replace("\\", "/"))
                  .append("'>Download</a></td>");
                sb.append("</tr>");
            }

            sb.append("</table>");
            sb.append("</body></html>");

            exchange.getResponseHeaders().set("Content-Type", "text/html");
            exchange.sendResponseHeaders(200, sb.length());
            OutputStream os = exchange.getResponseBody();
            os.write(sb.toString().getBytes());
            os.close();
        }

        private String formatFileSize(long size) {
            if (size < 1024) return size + " B";
            if (size < 1024 * 1024) return (size / 1024) + " KB";
            return (size / (1024 * 1024)) + " MB";
        }
    }

    private class DownloadHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange exchange) throws IOException {
            Map<String, String> params = queryToMap(exchange.getRequestURI().getQuery());
            String filePath = params.get("file");

            if (filePath == null || filePath.isEmpty()) {
                String response = "File parameter is missing";
                exchange.sendResponseHeaders(400, response.length());
                OutputStream os = exchange.getResponseBody();
                os.write(response.getBytes());
                os.close();
                return;
            }

            File file = new File(filePath);
            if (!file.exists() || !file.isFile()) {
                String response = "File not found: " + filePath;
                exchange.sendResponseHeaders(404, response.length());
                OutputStream os = exchange.getResponseBody();
                os.write(response.getBytes());
                os.close();
                return;
            }

            // Set headers
            exchange.getResponseHeaders().set("Content-Type", "application/vnd.android.package-archive");
            exchange.getResponseHeaders().set("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
            exchange.sendResponseHeaders(200, file.length());

            // Stream file
            try (FileInputStream fis = new FileInputStream(file);
                 OutputStream os = exchange.getResponseBody()) {
                byte[] buffer = new byte[4096];
                int count;
                while ((count = fis.read(buffer)) != -1) {
                    os.write(buffer, 0, count);
                }
            }
        }

        private Map<String, String> queryToMap(String query) {
            Map<String, String> result = new HashMap<>();
            if (query == null) return result;

            for (String param : query.split("&")) {
                String[] pair = param.split("=");
                if (pair.length > 1) {
                    result.put(pair[0], pair[1]);
                } else {
                    result.put(pair[0], "");
                }
            }
            return result;
        }
    }
}

2.4 主程序入口 (Main.java)

package com.example.apkservice;

import java.io.IOException;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("APK File Search and Download Service");
        System.out.print("Enter root directory to search for APK files: ");
        String rootPath = scanner.nextLine();

        System.out.print("Enter server port (default 8080): ");
        String portStr = scanner.nextLine();
        int port = portStr.isEmpty() ? 8080 : Integer.parseInt(portStr);

        try {
            // Search for APK files
            ApkSearcher searcher = new ApkSearcher();
            List<ApkFile> apkFiles = searcher.searchApkFiles(rootPath);

            System.out.println("Found " + apkFiles.size() + " APK files:");
            for (ApkFile apk : apkFiles) {
                System.out.println("- " + apk.getName() + " (" + apk.getSize() + " bytes)");
            }

            // Start HTTP server
            DownloadServer server = new DownloadServer(apkFiles, port);
            server.start();

            System.out.println("Press ENTER to stop the server...");
            scanner.nextLine();

            server.stop();
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
            e.printStackTrace();
        } finally {
            scanner.close();
        }
    }
}

3. Maven依赖配置 (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>apk-download-service</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- For APK parsing (optional) -->
        <dependency>
            <groupId>net.dongliu</groupId>
            <artifactId>apk-parser</artifactId>
            <version>2.6.10</version>
        </dependency>
    </dependencies>
</project>

4. 使用说明

  1. 编译并运行程序:
   mvn clean package
   java -jar target/apk-download-service-1.0-SNAPSHOT.jar
  1. 按照提示输入要搜索APK文件的根目录和服务器端口(默认8080)
  2. 程序会扫描指定目录下的所有APK文件并启动HTTP服务器
  3. 访问以下URL:
  • http://localhost:8080/ – 服务主页
  • http://localhost:8080/list – 查看APK文件列表
  • http://localhost:8080/download?file=/path/to/file.apk – 下载指定APK文件
  1. 按Enter键停止服务器

5. 扩展功能建议

  1. APK元数据解析:使用apk-parser库从APK文件中提取包名、版本号等元数据
  2. 安全认证:添加基本的HTTP认证保护下载服务
  3. 缓存机制:对频繁下载的文件实现缓存
  4. 日志记录:记录下载请求和错误
  5. 多线程优化:优化大文件下载时的性能
  6. REST API:提供JSON格式的API接口供其他程序调用

这个实现提供了一个完整的本地APK文件搜索和HTTP下载服务,可以根据实际需求进行进一步定制和扩展。

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞5 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容