【问题标题】:Upload Progress per seconds - Android每秒上传进度 - Android
【发布时间】:2017-02-23 17:07:30
【问题描述】:

我正在尝试在服务器上上传文件并通过这种方式显示每秒上传的字节数:

public void RunUploadTest () {
    try {
        URL url = new URL(serverLink);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("content-type", "video/mp4");

        for(int i =0; i<10; i++) {
            FileInputStream fis = new FileInputStream(myFileVideo);
            DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
            int bytesWrite = 0;
            byte[] buffer = new byte[512];
            Stopwatch timer = new Stopwatch();
            int read;
            while ((read = fis.read(buffer)) != -1&& timer.elapsedTime()<1000) {
                dos.write(buffer, 0, read);
                dos.flush();
                bytesWrite++;
            }
            Log.d("Upload", "Bytes written: " + bytesWrite*512);
        }
        fis.close();

    } catch (IOException e){
        e.printStackTrace();
    }
}

问题在于没有像我预期的那样计算上传了多少字节。 你知道为什么不工作吗?

【问题讨论】:

  • 您的预期如何?它如何计算?
  • 您可以将输入流转换为字节数组并以这种方式获取计数stackoverflow.com/a/1264756/1754020
  • 我希望每秒都能得到一个结果。相反,我从日志中读取了 D/Upload: bytes writtem: 1521152 十次,并且不是每秒都出现。 @DmytroGrynets
  • @EduardoDennis 我也尝试过这种方式,但结果是一样的:D/Upload: Byteswritten: 1521152 for 10 times.

标签: java android file-upload server


【解决方案1】:

如果你有 10 次相同的字节被写入,有 2 个选项:

  1. 您的文件在不到 1 秒的时间内写入;
  2. 您的elapsedTime 方法,以秒(例如)而不是毫秒为单位返回

你可能也不需要那个 for 循环,它会让你读取文件 10 次。

我会这样重写你的代码:

public void RunUploadTest () {
    try {
        URL url = new URL(serverLink);

        HttpURLConnection conn = (HttpURLConnection) url.openConnection();

        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setUseCaches(false);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("content-type", "video/mp4");

        FileInputStream fis = new FileInputStream(myFileVideo);
        DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
        int bytesWrite = 0;
        byte[] buffer = new byte[512];
        int read;
        while((read = fis.read(buffer))) {
            Stopwatch timer = new Stopwatch();
            while (timer.elapsedTime()<1) { //my guess here is that this method returns in seconds
                dos.write(buffer, 0, read);
                dos.flush();
                bytesWrite += read; //taken from Yoni Gross answer
            }
            Log.d("Upload", "Bytes written: " + bytesWrite);
        }
        fis.close();

    } catch (IOException e){
        e.printStackTrace();
    }
}

【讨论】:

  • 公共秒表() { start = System.currentTimeMillis(); } //返回自创建秒表以来经过的时间(以毫秒为单位) public int elapsedTime() { long now = System.currentTimeMillis(); return (int) (现在 - 开始); }
  • 这是我的秒表代码。这一切都以毫秒为单位。关于 for 循环,我需要获取 10 次不同时间上传的平均字节数。
  • 您的文件大小是多少?我测试了你的代码(我以前应该这样做过),并且只开始使用大于 32420864 字节(~=30Mb)的文件具有不同的值
  • 我已经测试了一个更大的文件,但我得到了错误:关于 dos.write(buffer, 0, read) 行的 java.lang.OutOfMemoryError。
  • 除此之外,我觉得很奇怪,它能够在我们尝试的每一刻为我们俩上传每秒 30 MB:发送的字节数,是一个取决于网络。它应该根据是否执行测试而改变:例如在 wifi 或移动网络上@ths
【解决方案2】:

您的代码存在一些问题:

1。你没数对

这是一个相对较小的问题,但您读/写的最后一个缓冲区可能不会是 512 字节长,因此您的计算将不准确。

你应该改变

    bytesWrite++;
}
Log.d("Upload", "Bytes written: " + bytesWrite*512);

    bytesWrite += read;
}
Log.d("Upload", "Bytes written: " + bytesWrite);

2。无论如何,您将在 1 秒后停止上传

以下条件:

while ((read = fis.read(buffer)) != -1&& timer.elapsedTime()<1000)

将在文件完成读取或经过 1 秒后停止。除非文件非常小,否则文件上传很可能会在 1 秒后停止。

我不完全确定您是想要每秒更新一次,还是只是平均一次。

在平均情况下,您应该将 while 条件更改为:

while (read = fis.read(buffer))

并将日志更改为:

float uploadRate = (float)(bytesWrite / timer.elapsedTime()) / 1000.0f;
String logString = String.format("Upload rate: %.2f bytes per second", uploadRate)
Log.d("Upload", logString);

如果你确实想每秒打印一次进度,你需要做一些更花哨和更昂贵的事情,比如:

while (read = fis.read(buffer)) {
    dos.write(buffer, 0, read);
    dos.flush();
    bytesWrite += read;
    if (timer.shouldPrintSecondsProgress(){
        Log.d("Upload", "Bytes written: " + bytesWrite);
    }
}

StopWatch.shouldPrintSecondsProgress 应该是这样的:

public boolean shouldPrintSecondsProgress(){
    int currentSecond = elapsedTime() / 1000;
    if (currentSecond == nextUpdate){ //I've ignored the > case, which is probably an error in our case
        nextUpdate++; //this is an int field, marking the next second cause update
        return true;
    }
    return false;
}

3。您可能只测量“发送”而不测量“上传”

当您发送所有数据并刷新请求流时,网络堆栈的某些层可能具有缓冲/异步行为。实际上,仅往返可能会影响计算的正确性。

最好在测量时间过去之前关闭输出流,和/或从服务器读取响应(这将确保上传完成)。

【讨论】:

  • 我试过但结果是一样的。无论如何,正如我所理解的,“write”方法从偏移量 0 开始在缓冲区中写入“read”字节。我的缓冲区有 512 个字节大,这就是为什么我只写了“Byteswrite++”
  • @FedericaMarini 你是对的,我没注意到。然而,这是不正确的。此外,我还进行了编辑以在您的代码中包含其他问题。
猜你喜欢
  • 2015-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-03
  • 2012-04-08
  • 2018-08-30
  • 1970-01-01
相关资源
最近更新 更多