繁体   English   中英

我在编写复制大文件时遇到问题

[英]I'm having trouble writing copy large files

我的代码有问题,我正在用 base 64 加密一个超过 300mb 的文件,但是当我打开 lra 加密文件时,我的应用程序出错

这是我的代码在字节上崩溃,我不明白为什么

private void encript(final File file) {
    new AsyncTask<Void, Void, Void>() {

        @Override
        protected Void doInBackground(Void[] p) {
            File new_file = null;
            try {
                new_file = new File(file.getAbsolutePath() + ".enc.txt");
                if (!new_file.exists()) {
                    new_file.createNewFile();
                }
                BufferedInputStream mInputStream = new BufferedInputStream(new FileInputStream(file));
                OutputStream mOutputStream = new DataOutputStream(new FileOutputStream(new_file));
                byte[] data = new byte[mInputStream.available()];
                int len = 0;
                
                while (true) {
                    len = mInputStream.read(data);
                    if (len > 0) {
                        mOutputStream.write(Base64.encode(data, 0, len, Base64.DEFAULT));
                    }
                    break;
                }
                mOutputStream.flush();
                if (mOutputStream != null) {
                    mOutputStream.close();
                }
                if (mInputStream != null) {
                    mInputStream.close();
                }
            } catch (Exception io) {
                Toast.makeText(MainActivity.this, io.toString(), Toast.LENGTH_LONG).show();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void res) {
            Toast.makeText(MainActivity.this, "Sucesss", Toast.LENGTH_LONG).show();
        }
    }.execute(new Void[0]);
    
}

请注意,您在这里所做的是对文件内容进行 Base64 编码。 不要以为有人不能轻而易举地破解这个(所谓的)“加密”。

您的尝试有很多问题。 我将通过更重要的 go:

    @Override
    protected Void doInBackground(Void[] p) {
        File new_file = null;
        try {

问题:您应该对资源使用try以避免资源泄漏。

            new_file = new File(file.getAbsolutePath() + ".enc.txt");
            if (!new_file.exists()) {
                new_file.createNewFile();
            }

问题:

  1. 一方面,不需要使用createNewFile预先创建一个output文件。 如果文件不存在,使用FileOutputStream打开文件将创建它。

  2. 另一方面,在文件的父目录不存在、不可写等情况下,这不会阻止(或报告)错误。

  3. 最好使用java.nio.file.Pathjava.nio.file.Files来自 Java 7 / Android API 26. PathFiles是更好的 API 报告,它们将报告问题作为例外假设,以便您可以(假设地)通过您的异常处理程序将它们发送给用户。

    甚至还有一些Files.copy方法,尽管它们并不直接适用于您的用例,因为您在复制数据时对数据进行编码。

     BufferedInputStream mInputStream = new BufferedInputStream(new FileInputStream(file)); OutputStream mOutputStream = new DataOutputStream(new FileOutputStream(new_file));

问题:

我认为您不需要DataOutputStream 它实际上不会做任何事情。

            byte[] data = new byte[mInputStream.available()];

问题:

available()方法不应该用于此。 它返回现在“可用”读取的字节数。 您获得的价值取决于上下文。 对于套接字 stream,它通常是当前在 kernel 缓冲区中准备读取的字节数。 对于“常规”文件,它可能是输入文件的长度。

因此,如果您正在复制一个“非常大”的文件,那么您可能会尝试分配一个缓冲区来容纳整个文件。 在最坏的情况下,这会导致您的应用程序 OOME!

注意- 这样的 OOME 可能是您看到的“无处不在”的问题。

“最佳”方法值得商榷,但我只会使用固定的缓冲区大小......如果我正在执行 stream 的显式读/写副本。缓冲区的大小会影响吞吐量,但如果你正在寻找最终性能你不应该这样做。

            int len = 0;
            
            while (true) {
                len = mInputStream.read(data);
                if (len > 0) {
                    mOutputStream.write(
                        Base64.encode(data, 0, len, Base64.DEFAULT));
                }
                break;
            }

问题:这个循环是完全错误的。 您在第一次迭代时无条件地中断。 你应该做这样的事情:

int len;
while ((len = mInputStream.read(data)) > 0) {
    mOutputStream.write(Base64.encode(data, 0, len, Base64.DEFAULT));
}

换句话说,继续读/写直到read返回非正结果。

注意:我不确定您在那里使用的是哪个Base64 class。 它似乎不是java.util.Base64

            mOutputStream.flush();
            if (mOutputStream != null) {
                mOutputStream.close();
            }
            if (mInputStream != null) {
                mInputStream.close();
            }

问题:

  1. flush()不是必需的。 关闭 stream 将刷新。 此外,如果mOutputStreamnull ,您尝试刷新会发生什么。

  2. 此版本泄漏资源(文件描述符)。 如果抛出异常,则不会执行这些语句,并且不会关闭 stream 对象。

  3. 如果您改用try with resources,则这一切都是不必要的。

     } catch (Exception io) { Toast.makeText(MainActivity.this, io.toString(), Toast.LENGTH_LONG).show(); } return null; }

问题:

  1. 捕捉Exception是个坏主意。 一个更好的想法是捕获并处理预期的异常,并让意外的异常传播,以便它们可以在堆栈的更高层进行处理。

    在这种情况下,您似乎假设异常是某种 I/O 异常。 事实上,它也可能是一个未经检查的异常,例如 NPE。 (OOME 也是可能的,尽管这个 catch 不会捕获它,因为 OOME 是Error异常。)

  2. 您正在丢弃异常详细信息。 应记录意外异常,以便您可以通过 logcat 诊断它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM