英文:
Azure blocklist contains 2 committed blocks but the result blob only shows the first block
问题
我正在使用 Azure 的 REST API 来执行 "put block" 和 "put block list" 操作,这些操作都成功完成了。我使用以下 URL 的 "get" 方法来验证:https://accountname.blob.core.windows.net/container/myblobname?comp=blocklist
结果如下:
<?xml version="1.0" encoding="utf-8"?>
<BlockList>
<CommittedBlocks>
<Block>
<Name>MjAyMy0wNy0xM1QxNTo0Mjo0MS4xM</Name>
<Size>1048057</Size>
</Block>
<Block>
<Name>MjAyMy0wNy0xM1QxNTo0MzoxMC44M</Name>
<Size>460893</Size>
</Block>
</CommittedBlocks>
</BlockList>
这两个块与一个视频文件相关。我的问题是,当我使用该 URL (https://accountname.blob.core.windows.net/container/myblobname) 获取整个视频时,它只返回第一个块,第二个块丢失了。问题出在哪里?
请求详细信息请见以下代码:
更新:以下是我的代码:
export const uploadLongFile = async (param) => {
// ...(你的代码)
};
const stageBlock = async (blockId, chunk, url, length) => {
// ...(你的代码)
};
const commitBlockList = async (blockIds, length, url) => {
// ...(你的代码)
};
如果你有其他问题或需要更多帮助,请告诉我。
英文:
I am using rest api of azure tu put block and also put block list, the operations finished successfully. I checked this with get method of this url https://accountname.blob.core.windows.net/container/myblobname?comp=blocklist
the result is:
<?xml version="1.0" encoding="utf-8"?>
<BlockList>
<CommittedBlocks>
<Block>
<Name>MjAyMy0wNy0xM1QxNTo0Mjo0MS4xM</Name>
<Size>1048057</Size>
</Block>
<Block>
<Name>MjAyMy0wNy0xM1QxNTo0MzoxMC44M</Name>
<Size>460893</Size>
</Block>
</CommittedBlocks>
</BlockList>
These 2 blocks are related to a video file. my problem is that when I use the url (https://accountname.blob.core.windows.net/container/myblobname) to get whole video it just return first block so the second one is missing. where is the problem?
request details
Updated: here is my code
export const uploadLongFile = async (param: any) => {
const {path, filename, mime} = param;
const blockSize = 1 * 1024 * 1024; // 1MB
const fileSize = param?.size;
const blockCount = Math.ceil(fileSize / blockSize);
const sasContainerUri = Config.CONTAINER_URI;
const customBlobName = Math.random().toString(16).slice(2);
const fileExtension = (filename ?? path).split('.').pop();
const newFileName = `${customBlobName}.${fileExtension}`;
const container = 'images';
const assetPath = `${sasContainerUri}/${container}/${newFileName}`;
const sasToken = Config.SAS_TOKEN; // you may need to play with other html verbs in this string e.g., `sp`, `ss` e.t.c.
const blockIds: any[] = [];
const videoChunks: any[] = [];
const timeInterval = param?.duration / 1000 / blockCount;
const chunks = await TrimWithIntervalVideo(path, timeInterval);// Trim video into blockCount chunks
let totalSize = 0;
for (let i = 0; i < blockCount; i++) {
let dataString = encodeURIComponent(encode(new Date().toISOString()));
blockIds.push(dataString);
let info = await ReactNativeBlobUtil.fs.stat(videoChunks[i]);
let chunkPath =
i < 10
? `${chunks?.url}00${i}.${chunks?.ext}`
: i < 100
? `${chunks?.url}0${i}.${chunks?.ext}`
: `${chunks?.url}${i}.${chunks?.ext}`;
videoChunks.push(chunkPath);
totalSize += info.size;
await stageBlock(
blockIds[i],
videoChunks[i],
`${assetPath}?${sasToken}`,
info?.size,
);
if (i === blockCount - 1) {
commitBlockList(blockIds, totalSize, `${assetPath}?${sasToken}`);
}
}
};
const stageBlock = async (
blockId?: any,
chunk?: any,
url?: any,
length?: any,
) => {
const res = await ReactNativeBlobUtil.fetch(
'PUT',
`${url}&comp=block&blockid=${blockId}`,
{
'x-ms-date': new Date().toUTCString(),
'content-length': `${length}`,
},
// Change BASE64 encoded data to a file path with prefix `ReactNativeBlobUtil-file://`.
// Or simply wrap the file path with ReactNativeBlobUtil.wrap(
ReactNativeBlobUtil.wrap(chunk),
).catch(error => console.log({error}));
console.log({res});
};
const commitBlockList = async (blockIds: any, length: any, url: any) => {
let blockList: any[] = blockIds?.map(
(value: string) => `<Latest>${value}</Latest>`,
);
let ff = blockList
.toString()
.replace('[', '')
.replace(']', '')
.replace(',', '\n');
console.log({url}, {blockList}, {ff});
const res2 = await ReactNativeBlobUtil.fetch(
'PUT',
`${url}&comp=blocklist`,
{
'x-ms-date': new Date().toUTCString(),
'content-length': `${length}`,
'content-type': 'text/plain; charset=UTF-8',
},
`<?xml version="1.0" encoding="utf-8"?>
<BlockList>
${ff}
</BlockList>`,
)
.progress((re, t) => console.log({re}, {t}))
.catch(error => console.log({error}));
console.log({res2});
};
答案1
得分: 0
感谢 @GauravMantri。我更改了提取块的方法,现在它运行良好。问题中的代码为每个块设置视频类型(例如chunk1.mp4),似乎Azure存储无法合并这些文件。因此,我将每个块存储为无类型,并更改了代码,现在它可以工作。
export const uploadLargeFile = async (param: any) => {
const { path, filename, mime } = param;
const blockSize = 1 * 1024 * 1024; // 1MB
const fileSize = param?.size;
const blockCount = Math.ceil(fileSize / blockSize);
const sasContainerUri = Config.sasContainerUri;
const customBlobName = Math.random().toString(16).slice(2);
const fileExtension = (filename ?? path).split('.').pop();
const newFileName = `${customBlobName}.${fileExtension}`;
const container = 'images';
const assetPath = `${sasContainerUri}/${container}/${newFileName}`;
const sasToken = Config.SAS_TOKEN; // you may need to play with other html verbs in this string e.g., `sp`, `ss` e.t.c.
const blockIds: any[] = [];
let totalSize = 0;
for (let i = 0; i < blockCount; i++) {
const blockId = btoa('block-' + i.toString().padStart(6, '0'));
blockIds.push(blockId);
const start = i * blockSize;
const end = Math.min(start + blockSize, fileSize);
let dest = `${ReactNativeBlobUtil.fs.dirs.CacheDir}/RIM3/d3_${i}`;
let file = await ReactNativeBlobUtil.fs.slice(path, dest, start, end);
let info = await ReactNativeBlobUtil.fs.stat(file);
const stageResult = await stageBlock(
blockId,
file,
`${assetPath}?${sasToken}`,
info?.size,
i,
blockCount,
param?.changeProgress,
);
if (!stageResult) {
showErrorMessage('Error upload file');
break;
}
totalSize += info.size;
console.log({ i });
if (i === blockCount - 1) {
const isSuccess = await commitBlockList(
blockIds,
fileSize,
`${assetPath}?${sasToken}`,
);
if (isSuccess) {
return newFileName;
} else {
return undefined;
}
}
}
};
希望这对你有帮助!
英文:
thanks to @GauravMantri . I change my method to extract chunks and it works fine. Code in the question set video type for each chunk (for example chunk1.mp4) it seems azure storage cannot merge these files. So I store each chunk without type and change code to this, now its working.
export const uploadLargeFile = async (param: any) => {
const {path, filename, mime} = param;
const blockSize = 1 * 1024 * 1024; // 1MB
const fileSize = param?.size;
const blockCount = Math.ceil(fileSize / blockSize);
const sasContainerUri = Config.sasContainerUri ;
const customBlobName = Math.random().toString(16).slice(2);
const fileExtension = (filename ?? path).split('.').pop();
const newFileName = `${customBlobName}.${fileExtension}`;
const container = 'images';
const assetPath = `${sasContainerUri}/${container}/${newFileName}`;
const sasToken = Config.SAS_TOKEN; // you may need to play with other html verbs in this string e.g., `sp`, `ss` e.t.c.
const blockIds: any[] = [];
let totalSize = 0;
for (let i = 0; i < blockCount; i++) {
const blockId = btoa('block-' + i.toString().padStart(6, '0'));
blockIds.push(blockId);
const start = i * blockSize;
const end = Math.min(start + blockSize, fileSize);
let dest = `${ReactNativeBlobUtil.fs.dirs.CacheDir}/RIM3/d3_${i}`;
let file = await ReactNativeBlobUtil.fs.slice(path, dest, start, end);
let info = await ReactNativeBlobUtil.fs.stat(file);
const stageResult = await stageBlock(
blockId,
file,
`${assetPath}?${sasToken}`,
info?.size,
i,
blockCount,
param?.changeProgress,
);
if (!stageResult) {
showErrorMessage('Error upload file');
break;
}
totalSize += info.size;
console.log({i});
if (i === blockCount - 1) {
const isSuccess = await commitBlockList(
blockIds,
fileSize,
`${assetPath}?${sasToken}`,
);
if (isSuccess) {
return newFileName;
} else {
return undefined;
}
}
}
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论