[英]I'm writing a battleship AI in Java and I'm having trouble troubleshooting
[英]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();
}
问题:
一方面,不需要使用createNewFile
预先创建一个output文件。 如果文件不存在,使用FileOutputStream
打开文件将创建它。
另一方面,在文件的父目录不存在、不可写等情况下,这不会阻止(或报告)错误。
最好使用java.nio.file.Path
和java.nio.file.Files
来自 Java 7 / Android API 26. Path
和Files
是更好的 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();
}
问题:
flush()
不是必需的。 关闭 stream 将刷新。 此外,如果mOutputStream
是null
,您尝试刷新会发生什么。
此版本泄漏资源(文件描述符)。 如果抛出异常,则不会执行这些语句,并且不会关闭 stream 对象。
如果您改用try with resources,则这一切都是不必要的。
} catch (Exception io) { Toast.makeText(MainActivity.this, io.toString(), Toast.LENGTH_LONG).show(); } return null; }
问题:
捕捉Exception
是个坏主意。 一个更好的想法是捕获并处理预期的异常,并让意外的异常传播,以便它们可以在堆栈的更高层进行处理。
在这种情况下,您似乎假设异常是某种 I/O 异常。 事实上,它也可能是一个未经检查的异常,例如 NPE。 (OOME 也是可能的,尽管这个 catch 不会捕获它,因为 OOME 是Error
异常。)
您正在丢弃异常详细信息。 应记录意外异常,以便您可以通过 logcat 诊断它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.