带有文本文件的Java fileoutputstream不完整

时间:2013-11-29 19:03:56

标签: java encryption fileoutputstream zipoutputstream

我正在编写一个加密和解密文件的小工具。加密文件将添加到zip-archive中。到目前为止,以下代码正在运行。我可以加密任何文件,但文本文件。如果我选择一个文本文件,那么它就是不完整的。如果有以下文字: "一两三测试检查测试"它变得像#34;一两三个测试che"。

没有异常抛出只缺少几个字节。任何其他文件(pdf,mp3,mp4,exe等)都是完整的。

package encryptme.crypto;

import encryptme.fileoperations.FileIn;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;

public class Encrypt {

    private String algorithm;
    private int keylength;
    private Key key;
    private KeyPair keypair;
    private File[] source;
    private String destination;

    public Encrypt(String a, int kl, Key k, File[] s, String dest) {
        this.algorithm = a;
        this.keylength = kl;
        this.key = k;
        this.source = s;
        this.destination = dest;
        this.output = o;
    }

    public void encOut() {
        CipherOutputStream cout = null;
        ZipOutputStream zout = null;
        OutputStream out = null;
        Cipher cipher;
        try {
            out = new FileOutputStream(this.destination);
            System.out.println(this.destination);
            zout = new ZipOutputStream(out);
            cipher = Cipher.getInstance(this.algorithm);
            cipher.init(Cipher.ENCRYPT_MODE, this.key);
            for (int i = 0; i < this.source.length; i++) {
                FileInputStream in = new FileInputStream(this.source[i].getAbsolutePath());
                ZipEntry ze = new ZipEntry(this.source[i].getName());                 
                zout.putNextEntry(ze);
                cout = new CipherOutputStream(zout, cipher);
                byte[] buffer = new byte[1024];
                long bytesRead = 0;
                for (bytesRead = 0; (bytesRead = in.read(buffer)) != -1;) {
                    cout.write(buffer, 0, (int) bytesRead);
                }
                zout.closeEntry();
                in.close();
            }
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchPaddingException ex) {
            Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (cout != null) {
                    cout.close();
                }
                if (zout != null) {
                    zout.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (IOException ex) {
                Logger.getLogger(Encrypt.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

使用jFileChooser选择要加密的文件,并将其添加到一个数组中,该数组作为参数传入上面的类。我想过将PrintWriter用于那些通过结尾识别它们的文本文件,例如&#39; TextFile.txt的&#39;或者&#39; textfile.odt&#39;。但是,如果文件没有像#text;&#39;

那样的结尾,我该怎么办?

我对Java和编码一般都很陌生,所以我希望有一个错误导致问题。

2 个答案:

答案 0 :(得分:0)

您需要在致电cout之前关闭zout.closeEntry,以便清除密码已缓冲的任何剩余数据。不幸的是,cout.close()会调用zout.close(),这是我们绝对不想要的,因为这会阻止您编写任何其他条目。

我会使用CloseShieldOutputStream from commons-io

cout = new CipherOutputStream(new CloseShieldOutputStream(zout), cipher);

此类旨在阻止close()调用传播到基础包装流(在本例中为zout)。

答案 1 :(得分:-1)

我不是100%肯定你的要求,但是你想要清理你收到的加密类文件吗?确实有一种方法是查看文件扩展名:

public class ImageFileFilter implements FileFilter {

        private String[] imageExtentions = {"png", "jpg", "gif" };

        @Override
        public boolean accept(File file) {
                for(String ext : imageExtentions){
                        if(file.isFile()){
                                if(file.getName().toLowerCase().endsWith(ext))
                                        return true;
                        }
                }
                return false;
        }
}

上面的示例是一个应该处理图像扩展的类,但它是通用的,因此它适用于传递给accept方法的任何扩展。关键是要实现FileFilter接口,然后您可以清理文件。

编辑: 啊,你编辑了你的问题,这使你更清楚你想要什么,这不是我给出的答案所解决的。