gpt4 book ai didi

java - Android 跟踪 Azure CloudBlockBlob 上传进度

转载 作者:行者123 更新时间:2023-11-29 19:16:14 25 4
gpt4 key购买 nike

如何在调用 blob.upload(new FileInputStream(imageFile), imageFile.length()); 后打印已上传的字节数?我想记录类似“已上传 100/totalBytes 字节,已上传 224/totalBytes 字节...”之类的内容,因此我可以创建上传进度的进度条。

这是代码:

//AzureBlobLoader 扩展 AsyncTask

public class AzureBlobUploader extends AzureBlobLoader {
private Activity act;
private String userName;
private TaggedImageObject img;
private Fragment histFragment;

public AzureBlobUploader(Fragment f, Activity act, String userName, TaggedImageObject img) {
super();
this.act = act;
this.userName = userName;
this.img = img;
this.histFragment = f;
}


@Override
protected Object doInBackground(Object[] params) {

File imageFile = new File(this.img.getImgPath());

try {

// Define the path to a local file.
final String filePath = imageFile.getPath();

// Create or overwrite the blob with contents from the local file.
String[] imagePathArray = filePath.split("/");
String imageName = imagePathArray[imagePathArray.length-1];

System.out.println("Image Name: " + imageName);

String containerName = userName + "/" + imageName;

System.out.println("Container Name: " + containerName);

CloudBlockBlob blob= this.getContainer().getBlockBlobReference(containerName);


//UPLOAD!
blob.upload(new FileInputStream(imageFile), imageFile.length());

//-----DATABASE-----//
//create client
this.setDBClient(
new MobileServiceClient(
"URL",
this.act.getApplicationContext()
)
);

this.setImageTable(this.getDBClient().getTable(Image.class));
this.setIcavTable(this.getDBClient().getTable(ICAV.class));

//IMG TABLE QUERY
String validImageID = containerName.replace("/", "_");
Log.d("Azure", "Valid Image ID: " + validImageID);

Image img = new Image(validImageID, this.img.getUser(), this.img.getLat(), this.img.getLon());
this.getImageTable().insert(img);

for(String context : this.img.getContextAttributeMap().keySet()){
Map<String,String> attributeValueMap = this.img.getContextAttributeMap().get(context);

for(String attribute : attributeValueMap.keySet()){
String value = attributeValueMap.get(attribute);


ICAV icavRow = new ICAV();
icavRow.setImageID(validImageID);
icavRow.setContextID(context);
icavRow.setAttributeID(attribute);
icavRow.setValue(value);

this.getIcavTable().insert(icavRow);
}

}
} catch (Exception e) {
System.out.println(e.toString());
}

return null;
}



@Override
protected void onProgressUpdate(Object... object) {
super.onProgressUpdate(object);
Log.d("progressUpdate", "progress: "+((Integer)object[0] * 2) + "%");
}

@Override
protected void onPostExecute(Object o) {
// to do


}

最佳答案

如您所见,Azure SDK 不直接允许这样做,但将您的输入流包装在另一个输入流中应该相当容易,该输入流可以为读取的字节提供回调。类似的东西:

public class ListenableInputStream extends InputStream {

private final InputStream wraped;
private final ReadListener listener;
private final long minimumBytesPerCall;
private long bytesRead;

public ListenableInputStream(InputStream wraped, ReadListener listener, int minimumBytesPerCall) {
this.wraped = wraped;
this.listener = listener;
this.minimumBytesPerCall = minimumBytesPerCall;
}


@Override
public int read() throws IOException {
int read = wraped.read();
if (read >= 0) {
bytesRead++;
}
if (bytesRead > minimumBytesPerCall || read == -1) {
listener.onRead(bytesRead);
bytesRead = 0;
}
return read;
}

@Override
public int available() throws IOException {
return wraped.available();
}

@Override
public void close() throws IOException {
wraped.close();
}

@Override
public synchronized void mark(int readlimit) {
wraped.mark(readlimit);
}

@Override
public synchronized void reset() throws IOException {
wraped.reset();
}

@Override
public boolean markSupported() {
return wraped.markSupported();
}

interface ReadListener {
void onRead(long bytes);
}
}

minimumBytesPerCall 应该用一些合理的数字初始化,因为您可能不希望在每个字节上都被调用,也许每半兆字节应该是好的。

请记住,这一切都是在 doInBackground 线程上调用的,因此请相应地采取行动。

编辑:

我已经编辑了上面的类,在计算 bytesRead 值时出现了一个小错误。官方文档解释你的后续问题https://developer.android.com/reference/java/io/InputStream.html#read()

Reads the next byte of data from the input stream

因此 read() 如果到达末尾则读取 1 个字节的数据(或返回 -1)。所以是的,必须多次调用它才能读取整个图像。

然后方法 onRead(long) get 在每次至少 minimumBytesPerCall 被读取时调用(这是为了避免回调每个字节)并再次调用流的结尾(当它返回 -1 时)

传递给 onRead(long) 的值是自上次调用以来已读取的数量。因此,在您的 AsyncTask 上实现它,您必须累加此值并与文件的总大小进行比较。

你的 asynctask 中类似下面的代码应该可以正常工作(假设 Progress 通用参数是一个 Long):

    private long fileLength;
private long totalBytes;

private final ListenableInputStream.ReadListener readListener = new ListenableInputStream.ReadListener() {
@Override
public void onRead(long bytes) {
totalBytes += bytes;
publishProgress(totalBytes);
}
};

并在您的上传部分中替换为:

FileInputStream fis = new FileInputStream(imageFile);
fileLength = imageFile.length();
ListenableInputStream lis = new ListenableInputStream(fi, readListener, 256 * 1024); // this will call onRead(long) every 256kb
blob.upload(lis, fileLength);

最后一点,请记住 CloudBlockBlob 内部只是将文件缓存在自己的内存中以供以后上传,或者做任何其他您无法控制的奇怪事情。这段代码所做的只是检查是否读取了完整的文件。

编码愉快!

关于java - Android 跟踪 Azure CloudBlockBlob 上传进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43441951/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com