在Linux中使用7-zip和Java压缩文件夹

lrpiutwd  于 2023-05-27  发布在  Java
关注(0)|答案(1)|浏览(159)

在我的代码中有以下函数。

public static void runExecutable(String filePath, String command, boolean commandLine, boolean wait) {
    
    InputStream inputStream = CommonMethods.class.getClassLoader().getResourceAsStream(filePath);
    String tempFileSuffix = "";
    switch (CommonMethods.getOperatingSystem()) {
        case "Windows":
            tempFileSuffix = ".exe";
            break;
        case "Linux":
        case "Mac":
            tempFileSuffix = ".bin";
            break;
    }
    
    
    
    File tempFile;
    try {
        tempFile = File.createTempFile("AutoFPCurator", tempFileSuffix);
    } catch (IOException e) {
        new ErrorDialog(e);
        return;
    }

    
    try (FileOutputStream outputStream = new FileOutputStream(tempFile)) {
        byte[] buffer = new byte[1024];
        int length;
        while ((length = inputStream.read(buffer)) > 0) {
            outputStream.write(buffer, 0, length);
        }
        outputStream.close();
    } catch (IOException e) {
        new ErrorDialog(e);
        return;
    }
    
    
    
    
    String cmdProgram = "";
    String cFlag = "-c";
    switch (CommonMethods.getOperatingSystem()) {
        case "Windows": 
            cmdProgram = "cmd.exe";
            cFlag = "/c";
            break;
        case "Mac":
            cmdProgram = "sh";
            break;
        case "Linux":
            cmdProgram = "bash";
            break;
        default:
            return;
    }
    
    ProcessBuilder processBuilder = !commandLine ? new ProcessBuilder(tempFile.getAbsolutePath(), command)
                            : new ProcessBuilder(cmdProgram, cFlag, tempFile.getAbsolutePath(), command);
    processBuilder.redirectErrorStream(true);
    
    
    Process process;
    try {
        process = processBuilder.start();
    } catch (IOException e) {
        new ErrorDialog(e);
        return;
    }
    if (!wait) {
        return;
    }
    
    
    try {
        process.waitFor();
    } catch (InterruptedException e) {
        new ErrorDialog(e);
    }
    
    
}

这段代码被设计为运行src/main/resources/中的可执行文件,正如它所指定的那样,但是它特别用于将文件夹压缩成7z文件(使用其src/main/resources目录中的独立7z可执行文件)。我使用可执行文件是因为为Java设计的7Z压缩算法(比如Apache Commons的),不像可执行文件那样,按照我需要的方式压缩它。我下载了Linux 7z可执行文件,解压缩它,并在程序中使用7zz)。当我这样称呼它时:

switch (CommonMethods.getOperatingSystem()) {
         case "Windows":
             exeString = "programs/7zip/7za.exe";
             break;
         case "Mac":
             exeString = "programs/7zip/7zzmac";
             break;
         case "Linux":
             exeString = "programs/7zip/7zznux";
             break;
         default:
             System.out.println(commonStrs.get("unsupportedOS"));
             return;
    }
    CommonMethods.runExecutable(exeString, args, true, true);

它在Windows上工作,但我在Linux上试过,它不工作。我一直在努力找出问题所在参数是有效的,它看起来确实在运行,但它只是不压缩文件夹。我运行了原始参数,该函数将自己构建到Linux终端中,它说“Permission denied”,以响应我试图访问tmp文件夹(临时7zip可执行文件存储的地方)。我试着把它存储在一个完全可以访问的备用位置,但无济于事。
TL;DR,我如何在Linux(和Mac的扩展,也许?))?需要说明的是,这在Windows上有效。

wgeznvg7

wgeznvg71#

在macOS(Ventura 13.4)上,我下载了7zz的可执行文件。然后我写了一个快速程序来验证我可以通过ProcessBuilder直接运行可执行文件(不需要sh)。这是成功的。
然后,我将7zz添加到应用程序资源中,并将其解压缩到临时文件中。由于文件不可执行(File#canExecutefalse),因此失败。
然后,基于How do I programmatically change file permissions?,我修改了临时文件的执行属性(在它被提取之后),这是成功的

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {
    public static void main(String[] args) {
        try {
            new Main();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InterruptedException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public Main() throws IOException, InterruptedException {
        File binary = extractBinary();
        System.out.println(binary);
        System.out.println("Executable: " + binary.canExecute());
        // This could be moved to extractBinary
        // But I wanted to demonstrate the difference between
        // the two binary.canExecute() statements
        Files.setPosixFilePermissions(binary.toPath(), PosixFilePermissions.fromString("rwxr-x---"));
        System.out.println("Executable: " + binary.canExecute());

        ProcessBuilder pb = new ProcessBuilder(
                binary.getAbsolutePath(), 
                "a", 
                "/Users/shane.whitehead/Downloads/Test.7z", 
                "/Users/shane.whitehead/Downloads/7z2300-mac.tar/*"
        );
        pb.redirectErrorStream(true);
        Process p = pb.start();
        InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
        consumer.start();

        p.waitFor();

        consumer.join();
        System.out.println(consumer.getOutput());
    }

    protected File extractBinary() throws IOException {
        File tempFile = File.createTempFile("7zBinary", ".bin");
        try (FileOutputStream fos = new FileOutputStream(tempFile); InputStream is = getClass().getResourceAsStream("/bin/7zz")) {
            is.transferTo(fos);
        }
        return tempFile;
    }

    // This is just here to make my life easier
    public class InputStreamConsumer extends Thread {

        private InputStream is;
        private IOException exp;
        private StringBuilder output;

        public InputStreamConsumer(InputStream is) {
            this.is = is;
        }

        @Override
        public void run() {
            int in = -1;
            output = new StringBuilder(64);
            try {
                while ((in = is.read()) != -1) {
                    output.append((char) in);
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                exp = ex;
            }
        }

        public StringBuilder getOutput() {
            return output;
        }

        public IOException getException() {
            return exp;
        }
    }
}

您可能会发现首先在每个平台上找到一个工作解决方案,然后围绕这些需求设计您的解决方案更容易,也许有一个基于平台生成ProcessBuilder的工厂作为一个想法。

相关问题